The MIND-USA clinical trial aims to define the role of antipsychotics in the management of delirium in critically ill patients, specifically comparing haloperidol (typical antipsychotic) and ziprasidone (atypical antipsychotic) to placebo. Further details can be found in both the trial listing on clinicaltrials.gov and on the Open Science Framework, which houses:

  • Full statistical analysis plan (registered version prior to treatment unblinding can be found here)
  • SOP for database locking
  • Links to code for data management and analysis
  • This full report
knitr::opts_chunk$set(message = FALSE, warning = FALSE)

suppressPackageStartupMessages(library(checkpoint))

## Set checkpoint: Packages on CRAN as of May 14, 2018 (Github-only packages
## also installed on this date)
options(repos = "https://mran.microsoft.com/snapshot/2018-05-14")
checkpoint("2018-05-14")

suppressPackageStartupMessages(library(knitr))
suppressPackageStartupMessages(library(dplyr))
suppressPackageStartupMessages(library(tidyr))
suppressPackageStartupMessages(library(purrr))
suppressPackageStartupMessages(library(forcats))
suppressPackageStartupMessages(library(glue))
suppressPackageStartupMessages(library(kableExtra))
suppressPackageStartupMessages(library(captioner))
suppressPackageStartupMessages(library(rms))
suppressPackageStartupMessages(library(naniar))
suppressPackageStartupMessages(library(sparkline))
suppressPackageStartupMessages(library(survminer))
suppressPackageStartupMessages(library(cmprsk))
suppressPackageStartupMessages(library(DT))
suppressPackageStartupMessages(library(extrafont))
suppressPackageStartupMessages(library(ggthemr)) ## Github only; cttobin/ggthemr
suppressPackageStartupMessages(library(JTHelpers))
  ## Github only; jenniferthompson/JTHelpers

## Hmisc setup for nicely printing summaryM output
mu <- markupSpecs$html

## Levels for sorting factor versions of treatment
## (A-C used for coding prior to treatment blind being broken)
trt_levels <- data.frame(
  trt_num = 1:3,
  trt_abc = LETTERS[1:3],
  trt_actual = c("Placebo", "Haloperidol", "Ziprasidone")
)

## -- ggplot palette/custom theme ----------------------------------------------
# ## Picked colors from/inspired by Flatly theme
# palette_colors <- c(
#   "dred"    = "#EA513B",
#   "dgreen"  = "#00BE9D",
#   "dblue"   = "#2595D6",
#   "dyellow" = "#F89B2F",
#   "lred"    = "#EF7A69",
#   "lgreen"  = "#00F1C7",
#   "lblue"   = "#4EAAE0",
#   "lyellow" = "#FAB360",
#   "dgray"   = "#2E3F4F",
#   "lgray"   = "#92A3A3"
# )

## Started with Flatly theme colors, moved to some I liked better
palette_colors <- c(
  "dpurple" = "#242249",
  "dred"    = "#B40F20",
  "dgray"   = "#2E3F4F",
  "dgreen"  = "#74A089",
  "dblue"   = "#1D77AB",
  "dyellow" = "#F89B2F",
  "lred"    = "#EF7A69",
  "lgreen"  = "#00F1C7",
  "lblue"   = "#4EAAE0",
  "lyellow" = "#FAB360",
  "lgray"   = "#92A3A3"
)

## Taken from the "berlin" color palette in the scico package
## scico::scico(9, palette = "berlin")
mindusa_trtcols_long <- c(
  "Ziprasidone" = "#7B321C",
  "Haloperidol" = "#286886",
  "Placebo" = "#180B09"
)

mindusa_trtcols_short <-
  set_names(mindusa_trtcols_long, c("Zip", "Hal", "Plac"))

## Use ggthemr to define the full palette
mindusa_palette <- ggthemr::define_palette(
  swatch = as.character(palette_colors),
  gradient = c(
    lower = "#F8CD2F",
    upper = as.character(palette_colors["dblue"]))
)

## Set ggplot2 theme options directly
basetext_size <- 13
basetext_family <- "Lato"
mindusa_theme <- function(base_size = basetext_size){
  theme_bw(base_size = base_size, base_family = basetext_family) +
    theme(
      text = element_text(colour = as.character(palette_colors["dgray"])),
      plot.title = element_text(face = "bold"),
      plot.caption = element_text(face = "italic"),
      panel.grid.major = element_line(colour = "#E7E9E9"),
      panel.grid.minor = element_line(colour = "#F4F5F5"),
      legend.position = "bottom",
      legend.direction = "horizontal",
      strip.text = element_text(
        face = "bold", colour = as.character(palette_colors["dgray"])
      ),
      strip.background = element_rect(
        colour = as.character(palette_colors["dgray"]), fill = "#B9C3C4"
      )
    )
}

## Set final palette, theme
ggthemr(mindusa_palette)
theme_set(mindusa_theme())

# ## Test it out
# ggplot(data = iris, aes(x = Sepal.Length)) +
#   facet_wrap(~ Species) +
#   geom_histogram(aes(fill = Species), binwidth = 1) +
#   labs(
#     title = "This is a test plot",
#     subtitle = "With iris data.",
#     caption = "Everyone loves iris data."
#   )
# 
# ggplot(data = iris, aes(x = Sepal.Length, y = Sepal.Width)) +
#   geom_point(aes(colour = Petal.Length)) +
#   labs(title = "Testing out continuous scale")

## Source general helper functions
source("mindusa_rct_helpers.R")

## Source functions for adjusted quantiles from orm() model fits
source("orm_functions.R")
## -- Table and figure captions ------------------------------------------------
table_nums <- captioner(prefix = "Table")
fig_nums <- captioner(prefix = "Figure")

table_nums(
  name = "screening", caption = "Overview of Screening, Exclusions & Randomization"
)
table_nums(name = "exclusions", caption = "Study Exclusions")
table_nums(name = "exc_other", caption = "'Other' Exclusions")
table_nums(
  name = "baseline_all",
  caption = "Demographic & ICU Admission Characteristics, All Consented Patients"
)
table_nums(
  name = "baseline_trt",
  caption = "Demographic & ICU Admission Characteristics, Randomized Patients"
)
table_nums(
  name = "icursn_other", caption = "Descriptions of 'Other' ICU Admission Reasons"
)
table_nums(
  name = "inhosp_trt",
  caption = "Intervention Period Characteristics by Treatment Group"
)
table_nums(
  name = "intervention_pt", caption = "Description of Intervention by Patient"
)
table_nums(
  name = "intervention_dose",
  caption = "Description of Intervention by Study Drug Dose"
)
table_nums(
  name = "dose_held_other",
  caption = "Reasons for Temporary Study Drug Hold due to 'Other'"
)
table_nums(
  name = "dose_permdc_other",
  caption = "Reasons for Study Drug Discontinuation due to 'Other'"
)
table_nums(name = "dcfd_orci", caption = "Adjusted Odds Ratios (95% CI), DCFDs")
table_nums(name = "dcfd_meds", caption = "Adjusted Medians (95% CI), DCFDs")

table_nums('package_info', caption = "Software Details")

fig_nums(
  name = "dcfds_unadj",
  caption = "Delirium/Coma-Free Days by Treatment Group"
)
## Analysis datasets are stored in an .Rdata file, originally created and stored
##  by create_rctdata.R in ../MINDUSADataMgmt.
load("analysisdata/rct.Rdata")

# ## For clinical coordinators to summarize: Which patients had study drug held
# ## and/or discontinued due to an AE?
# write.csv(
#   subset(ptsummary_df,
#          ever_held_ae | permdc_active_ae,
#          select = c(id, ever_held_ae, permdc_active_ae)),
#   file = "ae_holds.csv",
#   row.names = FALSE
# )

## Read in descriptions of drug holds/discontinuations documented as due to AEs
## Based on CSV created above, with additional columns supplemented by
##  clinical coordinators
## Original file was XLSX, saved to CSV; no further edits made from document
##  sent by coordinators
drug_aes <- read.csv(
  "analysisdata/ae_holds_BTP_CLS edits.csv", stringsAsFactors = FALSE
) %>%
  dplyr::select(1:6) %>%
  set_names(c("id", "ever_held_ae", "permdc_active_ae", "descrip_source",
              "description", "comments"))

## How many patients were randomized?
n_rand <- length(rand_pts)

## Add treatment groups to datasets as needed
rand_df$trt <- factor(
  rand_df$trt, levels = c("Placebo", "Haloperidol", "Ziprasidone")
)
ptsummary_df <- left_join(ptsummary_df, rand_df, by = "id")

## Create an indicator for whether randomized patients got antipsychotics
## *either* between ICU admission & consent, or between consent & randomization
## ICU admission -> consent: ptsummary_df$antipsyc_adm
## Consent -> randomization/DQ: ptsummary_df$antipsyc_ever_pr
ptsummary_df$antipsyc_adm_pr <- with(ptsummary_df, {
  factor_tf(antipsyc_adm | (!is.na(antipsyc_ever_pr) & antipsyc_ever_pr))
})

## Restrict assessments to only intervention period, before day 14; this is
## period DCFDs is calculated over
##   Mostly needed for end section on missingness, but also used to describe all
##   RASSes assessed by study staff (reviewer request)
pad_int_df <- daily_int_df %>%
  filter(intervention & study_status %in% c("Intervention", "Withdrawn")) %>%
  dplyr::select(id, redcap_event_name, study_day, study_status) %>%
  left_join(padasmts_df, by = c("id", "redcap_event_name"))

Screening, Consent, and Randomization


Because this trial aims to describe the association between antipsychotics and treatment of delirium (rather than prevention), patients were required to be delirious prior to being randomized to study drug. In order to treat delirium immediately once observed, however, patients (or their surrogates) were consented as soon as they met study inclusion criteria and were found not to meet exclusion criteria.

Upon consent, patients could be randomized any time in the following five days, provided: no exclusions were met within that time; the patient remained in the ICU; and they did eventually become delirious. Patients are considered “disqualified” if they left the ICU or the study (via discharge, death, or withdrawal) prior to experiencing delirium, or never experienced delirium in the five days following consent.

## -- Create a data frame with rows = various categories of patients -----------
## --  (screened, consented, etc), along with N, % of patients in each ---------

## Get total N in each category; result = df with 1 row, columns = categories
## This will be added to a "vertical" data.frame to use as denominators
screen_ns <- ptstatus_df %>%
  ## Only include patients who met screening criteria
  filter(screened) %>%
  ## Create indicators for each reason for disqualification; patients
  ## disqualified for meeting exclusion criteria are included in "excluded after
  ## consent" and will not be listed here
  mutate(
    dq_nodel =
      ifelse(!disqualified, NA, dq_reason == "No delirium within 5 days"),
    dq_icudc =
      ifelse(!disqualified, NA, dq_reason == "ICU discharge before delirium"),
    dq_diedwd =
      ifelse(!disqualified, NA, dq_reason == "Died/withdrew before delirium")
  ) %>%
  ## Select the categories we want
  dplyr::select(
    screened, excluded_imm, approached, refused, consented, excluded_later,
     disqualified, randomized, dq_nodel, dq_icudc, dq_diedwd,
    matches("^rand\\_"), -rand_list
  ) %>%
  summarize_all(sum, na.rm = TRUE)

## Create data.frame for final table, starting with horizontal df
screen_table <- screen_ns %>%
  ## Transpose to one row per category
  gather(key = "status", value = "npts") %>%
  ## Add potential denominators from horizontal df (need to replicate original
  ##  to get the same number of rows)
  bind_cols(bind_rows(rep(list(screen_ns), nrow(.)))) %>%
  mutate(
    ## Determine appropriate denominator for each category %
    denom = ifelse(status %in% c("excluded_imm", "approached"), screened,
            ifelse(status %in% c("refused", "consented"), approached,
            ifelse(status %in% c("excluded_later", "randomized", "disqualified"),
                   consented,
            ifelse(substr(status, 1, 4) == "rand", randomized,
            ifelse(substr(status, 1, 2) == "dq", disqualified, NA))))),
    ## Calculate %
    pctpts = round((npts / denom) * 100),
    ## More informative statuses
    status_label = case_when(
      status == "screened"       ~ "Screened within 72 hours of meeting inclusion criteria",
      status == "excluded_imm"   ~ "Excluded immediately (details below)",
      status == "approached"     ~ "Staff approached patient/surrogate",
      status == "refused"        ~ "Patient/surrogate refused consent",
      status == "consented"      ~ "Consented for study",
      status == "excluded_later" ~ "Excluded after consent (details below)",
      status == "disqualified"   ~ "Ineligible for randomization",
      status == "randomized"     ~ "Randomized to study drug",
      status == "rand_mv"        ~ "Invasive mechanical ventilation",
      status == "rand_nippv"     ~ "Non-invasive positive pressure ventilation",
      status == "rand_shock"     ~ "Requiring treatment for shock",
      status == "dq_nodel"       ~ "No delirium in 5 days after consent",
      status == "dq_icudc"       ~ "ICU discharge prior to delirium",
      status == "dq_diedwd"      ~ "Died/withdrew prior to delirium",
      TRUE ~ status
    ),
    ## Create character string with N (%)
    npct = ifelse(is.na(pctpts), format_comma(npts),
                  sprintf("%s (%s%%)", format_comma(npts), pctpts))
  ) %>%
  dplyr::select(status_label, npct)

## When did screening take place? Find first and last month
screening_months <- ptstatus_df %>%
  dplyr::select(screened, exc_month, exc_year, enroll_month, enroll_year) %>%
  mutate(screen_month = ifelse(!is.na(exc_month), exc_month, enroll_month),
         screen_year = ifelse(!is.na(exc_year), exc_year, enroll_year)) %>%
  filter(screened & !is.na(screen_month)) %>%
  arrange(screen_year, screen_month) %>%
  slice(c(1, n())) %>%
  mutate(monthyr = paste(month.name[screen_month], screen_year))

first_month <- screening_months %>% slice(1) %>% pull(monthyr)
last_month <- screening_months %>% slice(n()) %>% pull(monthyr)

Overview of Screening, Exclusions and Randomization

Table 1 presents patient flow information for the 20,914 patients who were screened with 72 hours of meeting inclusion criteria. Screening took place between December 2011 and August 2017.

Note on Intent To Treat Population

When the treatment blind was broken, we found that 4 patients who never met criteria for randomization were assigned a treatment group by the investigational pharmacy, unbeknownst to study and/or treatment teams, who considered the patients disqualified for appropriate reasons documented in the database. This assignment was done in the pharmacy only, with no study drug ever sent, no intervention done, and no outcomes tracked for these patients. Because these patients never met randomization criteria, they were never considered to be randomized or treated by site coordinators; as disqualified patients, they had no outcomes data tracked after the date of disqualification, and no study drug was given. They are included in the “Ineligible for Randomization” group below and are not included in the intent-to-treat population.

The 2 patients who were randomized but never received a dose of study drug are included in the ITT population.

N (%)
Screened within 72 hours of meeting inclusion criteria 20,914
Screened Patients
Excluded immediately (details below) 16,306 (78%)
Staff approached patient/surrogate 4,608 (22%)
Approached Patients
Patient/surrogate refused consent 3,425 (74%)
Consented for study 1,183 (26%)
Consented Patients
Excluded after consent (details below) 46 (4%)
Ineligible for randomization 571 (48%)
Randomized to study drug 566 (48%)
Reasons for Ineligibility
No delirium in 5 days after consent 257 (45%)
ICU discharge prior to delirium 246 (43%)
Died/withdrew prior to delirium 68 (12%)
Organ Failures Present at Randomization
Invasive mechanical ventilation 517 (91%)
Non-invasive positive pressure ventilation 13 (2%)
Requiring treatment for shock 156 (28%)
Note:
Patients could have none, one, or two of the listed organ failures present at randomization; percentages may not add up to 100%.

Study Exclusions

## Some exclusions aren't relevant for our purposes here:
## - Rapidly resolving organ failure, 72h eligibility period exceeded:
##     indicates patient did not meet screening criteria
## - Patient/surrogate refusal: not considered a study exclusion
## We're also interested in the *combined* version of some:
## - pregnancy + breast feeding (2a, 2b); look at exc_2 instead
## - all exclusions relating to time running out (9c, e, f); look at exc_9cef
exclusion_rsns <- paste0(
  "exc_",
  c("2_pregbf", "34_neuro", "5_torsadesqtc", "6_maintmeds", "7_nmsallergy",
    "8_death24", "9a_refusal_md", "9cef_time", "10_blind_lang", "11_prison",
    "12_coenroll", "13_iqcode", "14_screen", "99_other")
)

exc_table <- ptstatus_df %>%
  ## Select only exclusion indicators (overall + specific exclusions)
  dplyr::select(id, matches("^excluded\\_"), one_of(exclusion_rsns)) %>%
  
  ## Reshape to long format: one row per "time" of exclusion (ever, screening,
  ##  after consent)
  gather(key = "when", value = "excluded", excluded_imm:excluded_ever) %>%
  
  ## Count only patients who were actually excluded
  filter(excluded) %>%
  
  ## Get count of each exclusion by time point
  group_by(when) %>%
  summarise_at(vars(-id), sum_na) %>%
  ungroup %>%
  
  ## Reshape to long format: one row per time + exclusion
  gather(key = "exclusion", value = "nexc", matches("^exc\\_[0-9]+")) %>%
  
  mutate(
    ## Calculate % of exclusions at each time point for each possible exclusion
    pctexc = round((nexc / excluded) * 100),
    ## Formatting/text work
    npct = sprintf("%s (%s%%)", format_comma(nexc), pctexc),
    when = gsub("^excluded\\_", "", when),
    exclusion = case_when(
      exclusion == "exc_2_pregbf"      ~ "Pregnancy or breast feeding",
      exclusion == "exc_34_neuro"      ~ "Severe dementia or neurodegenerative disease",
      exclusion == "exc_5_torsadesqtc" ~ "History of Torsades or prolonged QTc",
      exclusion == "exc_6_maintmeds"   ~ "Maintenance therapy with antipsychotics/lithium",
      exclusion == "exc_7_nmsallergy"  ~ "History of NMS or allergy to study drugs",
      exclusion == "exc_8_death24"     ~ "Expected death within 24 hours",
      exclusion == "exc_9a_refusal_md" ~ "Attending physician refusal",
      exclusion == "exc_9cef_time"     ~ "No surrogate available within window",
      exclusion == "exc_10_blind_lang" ~ "Blind, deaf, or unable to speak English",
      exclusion == "exc_11_prison"     ~ "Incarceration",
      exclusion == "exc_12_coenroll"   ~ "Enrolled in a study ineligible for co-enrollment",
      exclusion == "exc_13_iqcode"     ~ "IQCODE score >= 4.5",
      exclusion == "exc_14_screen"     ~ "Screening failure",
      TRUE ~ "Other exclusion"
    )
  ) %>%
  dplyr::select(exclusion, when, npct) %>%
  spread(key = when, value = npct) %>%
  arrange(desc(as.numeric(gsub(",", "", gsub(" \\([0-9]+\\%\\)$", "", ever)))))

exc_colheads <- c(
  "Exclusion",
  sprintf("Ever\\\n(N = %s)", format_comma(sum_na(ptstatus_df$excluded_ever))),
  sprintf("At Screening\\\n(N = %s)", format_comma(sum_na(ptstatus_df$excluded_imm))),
  sprintf("After Consent\\\n(N = %s)", format_comma(sum_na(ptstatus_df$excluded_later)))
)

The vast majority of exclusions were found at the time of screening. Some patients were excluded after consent, if determined to have cognitive disability (indicated by an IQCODE score >= 4.5) or were discovered to have an exclusion criteria prior to randomization. For the 16,352 patients excluded from MINDUSA, Table 2 presents exclusions:

  1. At any point (column 1; % out of all exclusions)
  2. At the time of screening (column 2; % out of all screening exclusions)
  3. After consent (column 3; % out of all post-consent exclusions)

Patients could meet multiple exclusion criteria; therefore, column percentages may total more than 100%.

Exclusion Ever
(N = 16,352)
At Screening
(N = 16,306)
After Consent
(N = 46)
Severe dementia or neurodegenerative disease 4,566 (28%) 4,552 (28%) 14 (30%)
No surrogate available within window 3,365 (21%) 3,364 (21%) 1 (2%)
Expected death within 24 hours 2,516 (15%) 2,507 (15%) 9 (20%)
Maintenance therapy with antipsychotics/lithium 1,854 (11%) 1,847 (11%) 7 (15%)
History of Torsades or prolonged QTc 1,484 (9%) 1,476 (9%) 8 (17%)
Blind, deaf, or unable to speak English 1,259 (8%) 1,258 (8%) 1 (2%)
Attending physician refusal 840 (5%) 840 (5%) 0 (0%)
Enrolled in a study ineligible for co-enrollment 454 (3%) 453 (3%) 1 (2%)
Incarceration 414 (3%) 414 (3%) 0 (0%)
History of NMS or allergy to study drugs 197 (1%) 197 (1%) 0 (0%)
Pregnancy or breast feeding 145 (1%) 145 (1%) 0 (0%)
Other exclusion 90 (1%) 89 (1%) 1 (2%)
IQCODE score >= 4.5 10 (0%) 0 (0%) 10 (22%)
Screening failure 1 (0%) 0 (0%) 1 (2%)

“Other” Exclusions

To save space, reasons for “other” exclusions are collapsed below. (These explanations are taken directly from our database; potentially identifiable information, including dates, times and parenthetical details, have been redacted to preserve patient privacy.)

Reasons for “Other” Exclusions

Explanation for ‘other’ exclusion
Leaving MICU to go to SICU
Transfer to floor
Being transferred to another hospital by ambulance today
Going to rehab later in the day
Unknown, error with original entry
NA
Pt to be transfered hospitals due to Insurance
Guillain-Barre
Previous enrollment in this study
Comfort care
Enrollment Amortization
Study drug expired
pt. was tx’d to another hospital
Burn
Pt on home cpap setting
Transferred to OSH
Discharged to LTAC
Trach collar
extubated to heated trach collar
Pt died
DRESS
Pt deceased
Transferred out of ICU
discharged from ICU
Chronic trach; no increase of ventilation from baseline
Pt has significant history of psychosis; pmh of schizophrenia, depression, etc.; multiple psychiatric admissions.
No extra ventilation; on CPAP at home
On burn service now
Pre-existing mental psychosis
Transferred to OSH
Chronic ventilatory support
Ventilator dependent
Chronic trach + vent dependence
Transferred to OSH
Chronic vent dependency
Chronic Vent
Chronic vent-dependent
chronic vent
Ventilator dependent
Chronic vent
tx to OSH
Dress Syndrome
Chronic vent
Vent-dependent at baseline
Chronic vent via trach
Transferred to OSH
Vulnerable population
homeless
Unknown
FOC-neuro blocking agent
PT ON NIMBEX DRIP
NA
Unknown
Transfer out of ICU
Discharged from ICU
Also being transfered out of ICU
Tx out of ICU
Tx out of unit
Bath Salts forgotten delirium - contraindication with antipsychotics
under 18 years old
Patient with documented DRESS in chart
Consent refused for another clinical study. Family not approached
Enrolled in another RCT
Suicidal
Approached for another RCT
Transferred to another unit
Suicidal
Suicidal
Readmit patient. Been in ICU and intubated previously
UMI-xx/xx/xx - previously enrolled in MIND, screened xx/xx/xx
UMI-xx/xx/xx - previously enrolled in MIND, screened xx/xx/xx
pt. transferred to a non-participating ICU
Moved out of unit
study staff not available to complete study procedures on airborne isolation patient
transferred to another ICU
transferred to another ICU
transferred to another ICU
BEING DISCHARGED HOME ON THE VENTILATOR
MOVED OUT OF UNIT
MOVED OUT OF UNIT
MOVED OUT OF UNIT
SICU contact… declined research request due to multiple ortho studies recruiting potential candidate.
pre-existing dystonia with twisted neck of torticollis
Transferred out of unit
Pt transferred out of ICU
Patient transferred out
Pt transferred out of unit
Patient transfered out of the unit
transfered out of unit prior to consent
extubated for comfort care only
Primary team just discussed palliative care with spouse
72 hour period of eligibility was exceeded before LAR came
left for cath lab and will then be transferred to different floor
NA

Descriptions of the Cohorts


Due to our study design (described briefly in the previous section), a substantial number of patients gave consent to be in the study, but were unable to be randomized to treatment. Thus, we first describe demographics and ICU admission characteristics of all consented patients, comparing those randomized to those not randomized (Table 4). We then describe those characteristics, as well as the course of hospitalization, by treatment group among randomized patients only (Table 5 and Table 7).

Notes on Baseline Tables

Medical vs Surgical Patients: In both baseline tables, “surgical patients” met one or more of the following criteria:

  1. Recorded primary ICU admission reason involving “surgery”
  2. Emergency or elective surgery between hospital admission and ICU admission
  3. Went to the OR between ICU admission and study enrollment

AUDIT Questionnaire: This questionnaire was developed to be administered directly to the patient; out of necessity, we often administered it to surrogates, leading to missing data if a surrogate was unsure about the answer to a particular question. We have therefore calculated the score in two different ways: 1) if any question is missing, the total is missing; and 2) any missing questions are assumed to have a score of 0.

Randomized vs Non-Randomized Patients

No information after study disqualification was collected on patients who were not randomized; therefore, we can only describe demographic and ICU admission characteristics of these patients. Table 4 describes these characteristics for both all consented patients, and separately for patients who were and were not able to be randomized.

Demographic & ICU Admission Characteristics, All Consented Patients

## Do things to make the table pretty: Factor version of rand. indicator, labels
ptsummary_all_df2 <- ptsummary_all_df %>%
  left_join(rand_df, by = "id") %>%
  mutate(
    randomized_f = factor(
      as.numeric(ptsummary_all_df$randomized),
      levels = 0:1,
      labels = c("Not Randomized", "Randomized")
    )
  ) %>%
  mutate_at(
    vars(enroll_mv, enroll_nippv, enroll_shock),
    funs(factor(as.numeric(.), levels = 0:1, labels = c("No", "Yes")))
  )
    
label(ptsummary_all_df2$enroll_mv) <- "On invasive MV at consent"
label(ptsummary_all_df2$enroll_nippv) <- "On NIPPV at consent"
label(ptsummary_all_df2$enroll_shock) <- "Treatment for shock at consent"
label(ptsummary_all_df2$age_consent) <- "Age at consent"
label(ptsummary_all_df2$gender) <- "Gender"
label(ptsummary_all_df2$race_cat) <- "Race"
label(ptsummary_all_df2$ethnicity) <- "Ethnicity"
label(ptsummary_all_df2$english_level) <- "Fluency in English"
label(ptsummary_all_df2$education) <- "Education"
label(ptsummary_all_df2$insurance) <- "Insurance"
label(ptsummary_all_df2$bmi) <- "BMI"
label(ptsummary_all_df2$home_antipsyc) <- "On antipsychotics prior to admission"
label(ptsummary_all_df2$charlson_total) <- "Charlson Comorbidities Index"
label(ptsummary_all_df2$iqcode_total_ph) <- "IQCODE total score"
label(ptsummary_all_df2$adl_total_ph) <-
  "Katz Activities of Daily Living total score"
label(ptsummary_all_df2$faq_total_ph) <-
  "Functional Activities Questionnaire total score"
label(ptsummary_all_df2$audit_total_ph_complete) <-
  "AUDIT total score; incomplete questions considered missing"
label(ptsummary_all_df2$audit_total_ph_partial) <-
  "AUDIT total score; incomplete questions considered normal"
label(ptsummary_all_df2$frailty_f) <- "CSHA Clinical Frailty Score"
label(ptsummary_all_df2$icu_rsn) <- "Primary reason for ICU admission"
label(ptsummary_all_df2$med_surg) <- "Patient type"
label(ptsummary_all_df2$sofa_adm) <- "SOFA at ICU admission (imputed data)"
label(ptsummary_all_df2$cv_sofa_adm_f) <- "Cardiovascular SOFA at ICU admission"
label(ptsummary_all_df2$days_icuadm_enroll) <-
  "Days between ICU admission and consent"
label(ptsummary_all_df2$sofa_imp_consent) <-
  "SOFA on day of consent (imputed data)"
label(ptsummary_all_df2$cv_sofa_consent) <-
  "Cardiovascular SOFA on day of consent"
label(ptsummary_all_df2$apache_adm) <- "APACHE II at ICU admission"

## Do things to make the table pretty: Factor version of rand. indicator, labels
ptsummary_df2 <- ptsummary_df %>%
  left_join(
    dplyr::select(ptsummary_all_df, id, sofa_imp_consent, cv_sofa_consent),
    by = "id"
  ) %>%
  mutate(
    randomized_f = factor(
      as.numeric(ptsummary_df$randomized),
      levels = 0:1,
      labels = c("Not Randomized", "Randomized")
    )
  ) %>%
  mutate_at(
    vars(enroll_mv, enroll_nippv, enroll_shock),
    funs(factor(as.numeric(.), levels = 0:1, labels = c("No", "Yes")))
  )

label(ptsummary_df2$enroll_mv) <- "On invasive MV at consent"
label(ptsummary_df2$enroll_nippv) <- "On NIPPV at consent"
label(ptsummary_df2$enroll_shock) <- "Treatment for shock at consent"
label(ptsummary_df2$age_consent) <- "Age at consent"
label(ptsummary_df2$gender) <- "Gender"
label(ptsummary_df2$race_cat) <- "Race"
label(ptsummary_df2$ethnicity) <- "Ethnicity"
label(ptsummary_df2$english_level) <- "Fluency in English"
label(ptsummary_df2$education) <- "Education"
label(ptsummary_df2$insurance) <- "Insurance"
label(ptsummary_df2$bmi) <- "BMI"
label(ptsummary_df2$home_antipsyc) <- "On antipsychotics prior to admission"
label(ptsummary_df2$charlson_total) <- "Charlson Comorbidities Index"
label(ptsummary_df2$iqcode_total_ph) <- "IQCODE total score"
label(ptsummary_df2$adl_total_ph) <-
  "Katz Activities of Daily Living total score"
label(ptsummary_df2$faq_total_ph) <-
  "Functional Activities Questionnaire total score"
label(ptsummary_df2$audit_total_ph_complete) <-
  "AUDIT total score; incomplete questions considered missing"
label(ptsummary_df2$audit_total_ph_partial) <-
  "AUDIT total score; incomplete questions considered normal"
label(ptsummary_df2$frailty_f) <- "CSHA Clinical Frailty Score"
label(ptsummary_df2$icu_rsn) <- "Primary reason for ICU admission"
label(ptsummary_df2$med_surg) <- "Patient type"
label(ptsummary_df2$sofa_adm) <- "SOFA at ICU admission (imputed data)"
label(ptsummary_df2$cv_sofa_adm_f) <- "Cardiovascular SOFA at ICU admission"
label(ptsummary_df2$days_icuadm_rand) <-
  "Days between ICU admission and randomization"
label(ptsummary_df2$sofa_imp_consent) <- "SOFA on day of consent (imputed data)"
label(ptsummary_df2$cv_sofa_consent) <- "Cardiovascular SOFA on day of consent"
label(ptsummary_df2$apache_adm) <- "APACHE II at ICU admission"
label(ptsummary_df2$antipsyc_adm_pr) <-
  "Received open-label antipsychotics between ICU admission and randomization"
label(ptsummary_df2$sofa_imp_rand) <-
  "SOFA on day of randomization (imputed data)"
label(ptsummary_df2$cv_sofa_rand) <-
  "Cardiovascular SOFA on day of randomization"
label(ptsummary_df2$rass_rand) <- "RASS at randomization"

## Formula we'll use for both demographic/admission tables
admit_formula_lhs <- "enroll_mv + enroll_nippv + enroll_shock + age_consent + gender + race_cat + ethnicity + english_level + education + iqcode_total_ph + adl_total_ph + faq_total_ph + audit_total_ph_complete + audit_total_ph_partial + frailty_f + insurance + bmi + home_antipsyc + charlson_total + frailty_f + icu_rsn + med_surg + apache_adm + sofa_adm + cv_sofa_adm_f + days_icuadm_enroll + sofa_imp_consent + cv_sofa_consent"

## Add randomization info for randomized patients only
admit_formula_lhs_rand <- paste(
  admit_formula_lhs,
  "+ antipsyc_adm_pr + days_icuadm_rand + sofa_imp_rand + cv_sofa_rand + rass_rand"
)

my_html(
  summaryM(as.formula(paste(admit_formula_lhs, "randomized_f", sep = " ~ ")),
           data = ptsummary_all_df2,
           overall = TRUE),
  caption = "Demographic & ICU Admission Characteristics of Consented Patients"
)
Demographic & ICU Admission Characteristics of Consented Patients.
N
Not Randomized
N=571
Randomized
N=566
Combined
N=1137
On invasive MV at consent 1137
    No 26% 146 571 7% 38 566 16% 1841137
    Yes 74% 425 571 93% 528 566 84% 9531137
On NIPPV at consent 1137
    No 91% 518 571 97% 549 566 94% 10671137
    Yes 9% 53 571 3% 17 566 6% 701137
Treatment for shock at consent 1137
    No 66% 377 571 67% 379 566 66% 7561137
    Yes 34% 194 571 33% 187 566 34% 3811137
Age at consent 1134 49 59 68
57 ± 15
51 60 69
59 ± 14
50 60 68
58 ± 15
Gender 1134
    Male 54% 306 568 57% 323 566 55% 6291134
    Female 46% 262 568 43% 243 566 45% 5051134
Race 1134
    American Indian or Alaska Native 0% 2 568 1% 6 566 1% 81134
    Asian 1% 5 568 1% 4 566 1% 91134
    Black or African American 15% 87 568 13% 76 566 14% 1631134
    Native Hawaiian or Other Pacific Islander 0% 2 568 0% 0 566 0% 21134
    White 80% 452 568 83% 467 566 81% 9191134
    Multiple or other race(s) 4% 20 568 2% 13 566 3% 331134
Ethnicity 1134
    Hispanic or Latino 9% 51 568 8% 45 566 8% 961134
    Not Hispanic or Latino 91% 517 568 92% 521 566 92% 10381134
Fluency in English 1103
    Yes/primary 95% 516 546 96% 534 557 95% 10501103
    Secondary, well/very well 3% 14 546 2% 11 557 2% 251103
    Secondary, not well or fluency unknown 2% 9 546 1% 3 557 1% 121103
    No; Spanish only 1% 7 546 2% 9 557 1% 161103
Education 1089
    Less than high school 15% 82 542 17% 92 547 16% 1741089
    High school diploma/GED 38% 206 542 36% 199 547 37% 4051089
    Some college, no degree 21% 115 542 25% 137 547 23% 2521089
    Associate degree 7% 39 542 7% 36 547 7% 751089
    Bachelor's degree 11% 60 542 11% 61 547 11% 1211089
    Master's degree 4% 24 542 3% 15 547 4% 391089
    Doctorate (MD, PhD, JD, others) 3% 16 542 1% 7 547 2% 231089
IQCODE total score 1090 3.00 3.00 3.12
3.04 ± 0.45
3.00 3.00 3.25
3.14 ± 0.39
3.00 3.00 3.19
3.09 ± 0.42
Katz Activities of Daily Living total score 1086 0.00 0.00 1.00
1.22 ± 2.61
0.00 0.00 1.00
0.96 ± 1.98
0.00 0.00 1.00
1.09 ± 2.32
Functional Activities Questionnaire total score 1086 0.0 0.0 3.0
3.1 ± 6.1
0.0 0.0 5.0
3.8 ± 6.4
0.0 0.0 4.0
3.5 ± 6.3
AUDIT total score; incomplete questions considered missing 904 0.0 0.0 2.0
2.0 ± 5.2
0.0 0.0 2.0
3.1 ± 7.3
0.0 0.0 2.0
2.6 ± 6.4
AUDIT total score; incomplete questions considered normal 1070 0.0 0.0 2.0
2.3 ± 5.7
0.0 1.0 3.0
3.7 ± 7.8
0.0 0.0 2.0
3.0 ± 6.9
CSHA Clinical Frailty Score 1133
    Very fit 4% 24 567 3% 15 566 3% 391133
    Well 11% 63 567 12% 69 566 12% 1321133
    Well, with treated co-morbid disease 28% 159 567 27% 155 566 28% 3141133
    Apparently vulnerable 28% 160 567 28% 157 566 28% 3171133
    Mildly Frail 11% 61 567 14% 79 566 12% 1401133
    Moderately frail 14% 77 567 14% 77 566 14% 1541133
    Severely frail 4% 23 567 2% 14 566 3% 371133
Insurance 1134
    None 8% 43 568 6% 36 566 7% 791134
    Government/VHA 2% 13 568 3% 19 566 3% 321134
    Medicaid 15% 83 568 15% 87 566 15% 1701134
    Medicare + Medicaid 11% 65 568 8% 43 566 10% 1081134
    Medicare + Private 21% 118 568 23% 133 566 22% 2511134
    Medicare Only 13% 76 568 17% 99 566 15% 1751134
    Private Only 30% 170 568 26% 149 566 28% 3191134
BMI 1128 24 29 36
31 ± 12
24 29 36
32 ± 14
24 29 36
32 ± 13
On antipsychotics prior to admission 1134
    None 96% 547 568 96% 541 566 96% 10881134
    At least one 4% 21 568 4% 25 566 4% 461134
Charlson Comorbidities Index 1134 1.0 2.0 3.0
2.4 ± 2.3
1.0 2.0 4.0
2.5 ± 2.4
1.0 2.0 3.8
2.5 ± 2.3
Primary reason for ICU admission 1134
    Sepsis/Septic shock 20% 112 568 20% 111 566 20% 2231134
    ALI/ARDS d/t infection 11% 65 568 16% 91 566 14% 1561134
    ALI/ARDS w/o infection 6% 32 568 5% 27 566 5% 591134
    Airway protection/upper airway obstruction 21% 119 568 25% 143 566 23% 2621134
    COPD/Asthma 7% 40 568 4% 25 566 6% 651134
    Pulmonary other 11% 61 568 8% 46 566 9% 1071134
    CHF/cardiomyopathy 3% 15 568 1% 8 566 2% 231134
    Acute MI/Cardiogenic shock 2% 10 568 1% 8 566 2% 181134
    Arrhythmia 1% 3 568 0% 2 566 0% 51134
    GI bleed 2% 9 568 1% 7 566 1% 161134
    Renal failure 1% 5 568 1% 3 566 1% 81134
    Hemorrhagic shock 1% 3 568 0% 2 566 0% 51134
    Metabolic/Endocrine/Electrolyte 0% 1 568 1% 5 566 1% 61134
    Other infectious disease 1% 3 568 0% 1 566 0% 41134
    Cirrhosis/Hepatic failure 1% 5 568 2% 12 566 1% 171134
    Malignancy 1% 3 568 1% 4 566 1% 71134
    Seizures/Status epilepticus 1% 4 568 1% 3 566 1% 71134
    Neurological disease 1% 4 568 1% 3 566 1% 71134
    Vascular surgery 1% 5 568 1% 6 566 1% 111134
    Hepatobiliary/Pancreatic surgery 0% 2 568 2% 12 566 1% 141134
    Transplants 2% 14 568 2% 11 566 2% 251134
    Gastric surgery 1% 7 568 2% 11 566 2% 181134
    Colonic surgery 1% 5 568 1% 3 566 1% 81134
    Urologic surgery 1% 3 568 0% 1 566 0% 41134
    Orthopedic surgery 1% 6 568 0% 2 566 1% 81134
    ENT surgery 0% 1 568 1% 3 566 0% 41134
    OB/GYN surgery 0% 1 568 0% 0 566 0% 11134
    Other 5% 30 568 3% 16 566 4% 461134
Patient type 1134
    Medical 72% 409 568 72% 408 566 72% 8171134
    Surgical 28% 159 568 28% 158 566 28% 3171134
APACHE II at ICU admission 1134 20.0 25.0 30.2
25.7 ±  7.8
23.0 29.0 34.0
28.7 ±  7.7
22.0 27.0 33.0
27.2 ±  7.9
SOFA at ICU admission (imputed data) 1137 7.0 9.0 12.0
9.5 ±  4.0
8.0 11.0 13.8
10.9 ±  3.7
7.0 10.0 13.0
10.2 ±  4.0
Cardiovascular SOFA at ICU admission 1133
    MAP >/= 70 and No Pressors 15% 85 567 16% 89 566 15% 1741133
    MAP < 70 and No Pressors 40% 229 567 35% 200 566 38% 4291133
    Dop < 5 or dobutamine (any dose), milrinone (any dose), vasopressin (alone), phenylephrine (any dose) 6% 35 567 4% 25 566 5% 601133
    Dop > 5, epi/norepi < 0.1 16% 91 567 17% 99 566 17% 1901133
    Dop > 15, epi/norepi > 0.1, balloon pump 22% 127 567 27% 153 566 25% 2801133
Days between ICU admission and consent 566 0.89 1.57 2.55
1.90 ± 1.65
0.89 1.57 2.55
1.90 ± 1.65
SOFA on day of consent (imputed data) 1133 6.0 8.0 11.0
8.9 ±  3.9
7.0 10.0 13.0
10.3 ±  3.6
7.0 9.0 12.0
9.6 ±  3.8
Cardiovascular SOFA on day of consent 1131
    MAP >/= 70 and No Pressors 19% 109 566 20% 113 565 20% 2221131
    MAP < 70 and No Pressors 37% 209 566 35% 197 565 36% 4061131
    Dop < 5 or dobutamine (any dose), milrinone (any dose), vasopressin (alone), phenylephrine (any dose) 6% 35 566 5% 30 565 6% 651131
    Dop > 5, epi/norepi < 0.1 20% 116 566 19% 107 565 20% 2231131
    Dop > 15, epi/norepi > 0.1, balloon pump 17% 97 566 21% 118 565 19% 2151131
a b c represent the lower quartile a, the median b, and the upper quartile c for continuous variables. x ± s represents X ± 1 SD.   N is the number of non-missing values.

Randomized Patients by Treatment Group

The following tables describe demographic and ICU admission characteristics (Table 5) and in-hospital characteristics (Table 7) of all randomized patients.

Demographic & ICU Admission Characteristics, All Randomized Patients

Demographic & ICU Admission Characteristics of Randomized Patients.
N
Placebo
N=184
Haloperidol
N=192
Ziprasidone
N=190
Test Statistic
On invasive MV at consent 566 χ22=0.98, P=0.611
    No 8% 14184 7% 14192 5% 10190
    Yes 92% 170184 93% 178192 95% 180190
On NIPPV at consent 566 χ22=0.41, P=0.811
    No 97% 179184 96% 185192 97% 185190
    Yes 3% 5184 4% 7192 3% 5190
Treatment for shock at consent 566 χ22=1.2, P=0.561
    No 65% 119184 70% 134192 66% 126190
    Yes 35% 65184 30% 58192 34% 64190
Age at consent 566 52 59 67
59 ± 14
51 61 69
59 ± 14
50 61 69
59 ± 14
F2 563=0.05, P=0.952
Gender 566 χ22=0.14, P=0.931
    Male 58% 107184 56% 108192 57% 108190
    Female 42% 77184 44% 84192 43% 82190
Race 566 χ28=15, P=0.0651
    American Indian or Alaska Native 2% 3184 2% 3192 0% 0190
    Asian 0% 0184 1% 1192 2% 3190
    Black or African American 14% 26184 12% 23192 14% 27190
    Native Hawaiian or Other Pacific Islander 0% 0184 0% 0192 0% 0190
    White 83% 153184 85% 163192 79% 151190
    Multiple or other race(s) 1% 2184 1% 2192 5% 9190
Ethnicity 566 χ22=0.09, P=0.951
    Hispanic or Latino 8% 14184 8% 15192 8% 16190
    Not Hispanic or Latino 92% 170184 92% 177192 92% 174190
Fluency in English 557 χ26=7.3, P=0.291
    Yes/primary 96% 176183 96% 181189 96% 177185
    Secondary, well/very well 2% 3183 2% 3189 3% 5185
    Secondary, not well or fluency unknown 0% 0183 2% 3189 0% 0185
    No; Spanish only 2% 4183 1% 2189 2% 3185
Education 547 χ212=9.2, P=0.691
    Less than high school 16% 29181 19% 35184 15% 28182
    High school diploma/GED 36% 65181 36% 66184 37% 68182
    Some college, no degree 28% 50181 23% 42184 25% 45182
    Associate degree 9% 17181 4% 8184 6% 11182
    Bachelor's degree 8% 15181 14% 25184 12% 21182
    Master's degree 2% 3181 3% 6184 3% 6182
    Doctorate (MD, PhD, JD, others) 1% 2181 1% 2184 2% 3182
IQCODE total score 557 3.00 3.06 3.25
3.15 ± 0.40
3.00 3.00 3.19
3.09 ± 0.39
3.00 3.06 3.31
3.18 ± 0.39
F2 554=1.4, P=0.262
Katz Activities of Daily Living total score 547 0.00 0.00 1.00
0.86 ± 1.74
0.00 0.00 1.00
1.10 ± 2.19
0.00 0.00 1.00
0.93 ± 1.97
F2 544=0.57, P=0.572
Functional Activities Questionnaire total score 548 0.0 0.0 6.0
4.0 ± 6.6
0.0 0.0 5.0
3.5 ± 6.0
0.0 0.0 5.0
3.9 ± 6.7
F2 545=0.29, P=0.752
AUDIT total score; incomplete questions considered missing 452 0.0 1.0 3.0
3.7 ± 8.0
0.0 0.0 2.0
2.5 ± 6.3
0.0 0.0 2.0
3.2 ± 7.6
F2 449=2.2, P=0.122
AUDIT total score; incomplete questions considered normal 542 0.0 1.0 4.0
4.3 ± 8.3
0.0 0.0 2.0
3.0 ± 7.0
0.0 0.0 2.2
3.9 ± 8.1
F2 539=1.8, P=0.172
CSHA Clinical Frailty Score 566 χ212=11, P=0.531
    Very fit 3% 6184 2% 4192 3% 5190
    Well 11% 21184 14% 26192 12% 22190
    Well, with treated co-morbid disease 28% 51184 29% 55192 26% 49190
    Apparently vulnerable 24% 44184 27% 51192 33% 62190
    Mildly Frail 19% 35184 12% 24192 11% 20190
    Moderately frail 12% 22184 14% 26192 15% 29190
    Severely frail 3% 5184 3% 6192 2% 3190
Insurance 566 χ212=14, P=0.331
    None 9% 16184 6% 11192 5% 9190
    Government/VHA 4% 8184 2% 3192 4% 8190
    Medicaid 15% 28184 14% 27192 17% 32190
    Medicare + Medicaid 5% 9184 8% 15192 10% 19190
    Medicare + Private 22% 40184 23% 44192 26% 49190
    Medicare Only 18% 33184 21% 41192 13% 25190
    Private Only 27% 50184 27% 51192 25% 48190
BMI 564 24 30 36
32 ± 14
25 29 36
33 ± 16
24 29 36
32 ± 13
F2 561=0.26, P=0.772
On antipsychotics prior to admission 566 χ22=1.5, P=0.481
    None 97% 178184 96% 184192 94% 179190
    At least one 3% 6184 4% 8192 6% 11190
Charlson Comorbidities Index 566 1.00 2.00 4.00
2.57 ± 2.48
0.75 2.00 3.00
2.35 ± 2.33
1.00 2.00 4.00
2.67 ± 2.37
F2 563=1.2, P=0.292
Primary reason for ICU admission 566 χ252=62, P=0.161
    Sepsis/Septic shock 19% 35184 22% 43192 17% 33190
    ALI/ARDS d/t infection 17% 31184 17% 32192 15% 28190
    ALI/ARDS w/o infection 4% 8184 6% 12192 4% 7190
    Airway protection/upper airway obstruction 29% 53184 24% 46192 23% 44190
    COPD/Asthma 4% 7184 2% 4192 7% 14190
    Pulmonary other 9% 16184 8% 16192 7% 14190
    CHF/cardiomyopathy 1% 2184 2% 4192 1% 2190
    Acute MI/Cardiogenic shock 2% 4184 1% 1192 2% 3190
    Arrhythmia 0% 0184 1% 1192 1% 1190
    GI bleed 1% 1184 1% 1192 3% 5190
    Renal failure 0% 0184 1% 2192 1% 1190
    Hemorrhagic shock 1% 1184 1% 1192 0% 0190
    Metabolic/Endocrine/Electrolyte 1% 2184 1% 2192 1% 1190
    Other infectious disease 0% 0184 1% 1192 0% 0190
    Cirrhosis/Hepatic failure 3% 6184 2% 3192 2% 3190
    Malignancy 0% 0184 0% 0192 2% 4190
    Seizures/Status epilepticus 0% 0184 1% 2192 1% 1190
    Neurological disease 1% 1184 1% 2192 0% 0190
    Vascular surgery 1% 1184 2% 3192 1% 2190
    Hepatobiliary/Pancreatic surgery 2% 3184 2% 4192 3% 5190
    Transplants 1% 1184 1% 1192 5% 9190
    Gastric surgery 3% 5184 2% 3192 2% 3190
    Colonic surgery 1% 1184 0% 0192 1% 2190
    Urologic surgery 1% 1184 0% 0192 0% 0190
    Orthopedic surgery 0% 0184 0% 0192 1% 2190
    ENT surgery 1% 1184 1% 2192 0% 0190
    OB/GYN surgery 0% 0184 0% 0192 0% 0190
    Other 2% 4184 3% 6192 3% 6190
Patient type 566 χ22=0.29, P=0.871
    Medical 72% 132184 73% 141192 71% 135190
    Surgical 28% 52184 27% 51192 29% 55190
APACHE II at ICU admission 566 24.0 30.0 34.0
29.1 ±  7.3
23.0 28.5 34.0
28.5 ±  7.9
23.0 28.0 34.0
28.6 ±  8.0
F2 563=0.47, P=0.622
SOFA at ICU admission (imputed data) 566 8.0 11.0 14.0
11.2 ±  3.8
8.0 11.0 13.0
10.9 ±  3.6
8.0 10.0 13.0
10.7 ±  3.8
F2 563=1.3, P=0.262
Cardiovascular SOFA at ICU admission 566 χ28=3, P=0.931
    MAP >/= 70 and No Pressors 17% 31184 14% 26192 17% 32190
    MAP < 70 and No Pressors 35% 64184 35% 67192 36% 69190
    Dop < 5 or dobutamine (any dose), milrinone (any dose), vasopressin (alone), phenylephrine (any dose) 5% 10184 4% 7192 4% 8190
    Dop > 5, epi/norepi < 0.1 16% 30184 20% 39192 16% 30190
    Dop > 15, epi/norepi > 0.1, balloon pump 27% 49184 28% 53192 27% 51190
days_icuadm_enroll 566 0.88 1.51 2.40
1.77 ± 1.28
0.89 1.55 2.49
1.98 ± 2.09
0.94 1.67 2.68
1.94 ± 1.46
F2 563=1.1, P=0.352
SOFA on day of consent (imputed data) 565 8.0 10.0 14.0
10.7 ±  3.8
7.0 10.0 13.0
10.2 ±  3.5
7.0 9.0 12.0
10.0 ±  3.5
F2 562=1.7, P=0.192
Cardiovascular SOFA on day of consent 565 χ28=5.4, P=0.711
    MAP >/= 70 and No Pressors 19% 35184 22% 43192 19% 35189
    MAP < 70 and No Pressors 37% 68184 31% 59192 37% 70189
    Dop < 5 or dobutamine (any dose), milrinone (any dose), vasopressin (alone), phenylephrine (any dose) 5% 9184 6% 11192 5% 10189
    Dop > 5, epi/norepi < 0.1 16% 30184 19% 36192 22% 41189
    Dop > 15, epi/norepi > 0.1, balloon pump 23% 42184 22% 43192 17% 33189
Received open-label antipsychotics between ICU admission and randomization 566 χ22=0.33, P=0.851
    Yes 10% 18184 10% 20192 12% 22190
    No 90% 166184 90% 172192 88% 168190
Days between ICU admission and randomization 566 1.4 2.2 3.4
2.5 ± 1.6
1.5 2.4 3.4
2.8 ± 2.3
1.5 2.5 3.4
2.8 ± 1.9
F2 563=1.1, P=0.322
SOFA on day of randomization (imputed data) 566 7.0 10.0 13.0
10.2 ±  3.8
7.0 9.0 12.0
9.9 ±  3.6
7.0 9.0 12.0
9.7 ±  3.5
F2 563=0.92, P=0.42
Cardiovascular SOFA on day of randomization 565 χ28=1.7, P=0.991
    MAP >/= 70 and No Pressors 24% 44183 23% 44192 26% 50190
    MAP < 70 and No Pressors 38% 70183 37% 71192 36% 68190
    Dop < 5 or dobutamine (any dose), milrinone (any dose), vasopressin (alone), phenylephrine (any dose) 4% 7183 6% 11192 5% 10190
    Dop > 5, epi/norepi < 0.1 17% 32183 19% 37192 18% 34190
    Dop > 15, epi/norepi > 0.1, balloon pump 16% 30183 15% 29192 15% 28190
RASS at randomization 562 χ212=12, P=0.471
    -3 40% 73183 31% 60191 33% 62188
    -2 25% 45183 31% 59191 33% 62188
    -1 13% 24183 20% 39191 18% 33188
    0 10% 19183 7% 14191 8% 15188
    1 8% 14183 5% 10191 4% 8188
    2 3% 6183 3% 6191 4% 7188
    3 1% 2183 2% 3191 1% 1188
a b c represent the lower quartile a, the median b, and the upper quartile c for continuous variables. x ± s represents X ± 1 SD.   N is the number of non-missing values.
Tests used: 1Pearson test; 2Kruskal-Wallis test .

Descriptions of “Other” ICU Admission Reasons

To save space, reasons for “other” ICU admission among randomized patients are collapsed.

“Other” Reasons for ICU Admission

Explanation for ‘other’ ICU admission reason
Hypoxia, Respiratory Failure and Pulmonary edema
Altered Mental Status due to head trauma
Vomitting (airway protection), cardiac arrest, perforated stomach ulcer
Altered mental status due to polysubtstance overdose
Shortness of breath
Intubated 2/2 altered mental status and acidemia
OR
Acute Respiratory Failure
Acedemia
APL Differentiation Syndrome
plastic surgery, panniculectomy with hernia repair
Intubated to facilitate safe placement of VAS CATH for CRRT (subject with “severe delirium”)
hemodynamic instability, respiratory distress, and GI bleed, EGD
hypotension, hypothermia, bradycardia
Respiratory Failure
pulmonary hypertension

Intervention Period Characteristics by Treatment Group

Unless otherwise specified, quantities in this table reflect the 14 days including and following randomization (the “study period”). Additional notes:

  • “Liberation from mechanical ventilation” variables apply only to patients who were on either type of MV when randomized, or were placed on MV within the 24 hours following randomization.
  • “Successful” ICU and hospital discharge indicates discharge followed by at least 48 hours alive.
  • All time-to-event descriptions (eg, ICU length of stay) begin at the time of randomization and go through the entire hospitalization (even if the patient remained hospitalized after the intervention period).
  • “Antipsychotics” refers not only to open-label haloperidol and ziprasidone, but any antipsychotic, including quetiapine, aripiprazole, olanzapine, and risperidone. Doses are converted to haloperidol equivalents.
  • “Benzodiazepines” includes midazolam, lorazepam, and diazepam, all converted to midazolam equivalents.
  • “Opioids” includes fentanyl, remifentanil, morphine, and hydromorphone, all converted to fentanyl equivalents.

All drug conversion formulas can be found here.

## Which variables do we want for *all* drugs?
medsum_vars <- c("ever_int", "days_exp_int", "total_exp_int", "mean_exp_int")

inhosp_vars <- c(
  "ever_mv", "days_mv_exp", "mv_num", "int_num", "noninv_num", "on_mv_rand24",
  "ever_mvlib_rand24", "daysto_mvlib_exp", "sepsis", "stroke",
  paste("benzo", medsum_vars, sep = "_"),
  paste("opioid", medsum_vars, sep = "_"),
  paste("propofol", medsum_vars, sep = "_"),
  paste("dex", medsum_vars, sep = "_"),
  paste("halop", medsum_vars, sep = "_"),
  paste("zipras", medsum_vars, sep = "_"),
  paste("antipsyc", medsum_vars, sep = "_"),
  "sofa_imp_max_int", "sofa_imp_min_int", "sofa_imp_mean_int",
  "ever_del_int", "del_int_exp", "ever_hyperdel_int", "hyperdel_int_exp",
  "ever_hypodel_int", "hypodel_int_exp", "ever_coma_int", "coma_int_exp",
  "ever_delcoma_int", "delcoma_int_exp", "dcfd_int",
  "icu_los", "event_icudis_90", "tte_icudis_90_exp",
  "icu_readmit_number", "daysto_readm_exp",
  "hosp_los", "event_hospdis_90", "tte_hospdis_90_exp",
  "dc_status", "hospdis_loc", "daysto_death_ih",
  "event_death_30", "event_death_90"
)

## Create new dataset with variable labels, factors
inhosp_desc_df <- ptsummary_df %>%
  mutate(
    ever_mv = factor_tf(ever_mv),
    on_mv_rand24 = factor_tf(on_mv_rand24),
    ever_mvlib_rand24 = factor_tf(ever_mvlib_rand24),
    benzo_ever_int = factor_tf(benzo_ever_int),
    opioid_ever_int = factor_tf(opioid_ever_int),
    propofol_ever_int = factor_tf(propofol_ever_int),
    dex_ever_int = factor_tf(dex_ever_int),
    halop_ever_int = factor_tf(halop_ever_int),
    zipras_ever_int = factor_tf(zipras_ever_int),
    antipsyc_ever_int = factor_tf(antipsyc_ever_int),
    ever_del_int = factor_tf(ever_del_int),
    ever_hyperdel_int = factor_tf(ever_hyperdel_int),
    ever_hypodel_int = factor_tf(ever_hypodel_int),
    ever_coma_int = factor_tf(ever_coma_int),
    ever_delcoma_int = factor_tf(ever_delcoma_int),
    event_icudis_90 =
      factor_tf(!is.na(ftype_icudis_90) & ftype_icudis_90 == "ICU Discharge"),
    event_hospdis_90 = factor_tf(
      !is.na(ftype_hospdis_90) & ftype_hospdis_90 == "Hospital Discharge"
    ),
    event_death_30 = factor_tf(event_death_30),
    event_death_90 = factor_tf(event_death_90),
    
    ## Create descriptive versions of time-to-event variables:
    ## Want y/n version of failure type; if patient experienced event, want
    ##  new variable with only those event times
    tte_icudis_90_exp =
      ifelse(ftype_icudis_90 == "ICU Discharge", tte_icudis_90, NA),
    tte_hospdis_90_exp =
      ifelse(ftype_hospdis_90 == "Hospital Discharge", tte_hospdis_90, NA)
  )
label(inhosp_desc_df$ever_mv) <-
  "Ever on mechanical ventilation (either type), entire hospitalization"
label(inhosp_desc_df$days_mv_exp) <-
  "Days on mechanical ventilation (either type), entire hospitalization"
label(inhosp_desc_df$mv_num) <-
  "Times MV initiated (either type), entire hospitalization"
label(inhosp_desc_df$int_num) <- "Number of intubations, entire hospitalization"
label(inhosp_desc_df$noninv_num) <-
  "Times NIPPV initiated, entire hospitalization"
label(inhosp_desc_df$on_mv_rand24) <- "On MV at or within 24h of randomization"
label(inhosp_desc_df$ever_mvlib_rand24) <-
  "Ever successfully liberated from MV at randomization"
label(inhosp_desc_df$daysto_mvlib_exp) <-
  "Days to successful liberation from MV, entire hospitalization"
label(inhosp_desc_df$sepsis) <-
  "Met criteria for sepsis on or before Intervention Day 18"
label(inhosp_desc_df$stroke) <- "Had a stroke during hospitalization"
label(inhosp_desc_df$benzo_ever_int) <- "Received benzodiazepines"
label(inhosp_desc_df$benzo_days_exp_int) <-
  "Days received benzodiazepines, if at all"
label(inhosp_desc_df$benzo_total_exp_int) <-
  "Total dose of benzodiazepines, if any"
label(inhosp_desc_df$benzo_mean_exp_int) <-
  "Mean daily dose of benzodiazepines on days received"
label(inhosp_desc_df$opioid_ever_int) <- "Received opioids"
label(inhosp_desc_df$opioid_days_exp_int) <- "Days received opioids, if at all"
label(inhosp_desc_df$opioid_total_exp_int) <- "Total dose of opioids, if any"
label(inhosp_desc_df$opioid_mean_exp_int) <-
  "Mean daily dose of opioids on days received"
label(inhosp_desc_df$propofol_ever_int) <- "Received propofol"
label(inhosp_desc_df$propofol_days_exp_int) <-
  "Days received propofol, if at all"
label(inhosp_desc_df$propofol_total_exp_int) <- "Total dose of propofol, if any"
label(inhosp_desc_df$propofol_mean_exp_int) <-
  "Mean daily dose of propofol on days received"
label(inhosp_desc_df$dex_ever_int) <- "Received dexmedetomidine"
label(inhosp_desc_df$dex_days_exp_int) <-
  "Days received dexmedetomidine, if at all"
label(inhosp_desc_df$dex_total_exp_int) <-
  "Total dose of dexmedetomidine, if any"
label(inhosp_desc_df$dex_mean_exp_int) <-
  "Mean daily dose of dexmedetomidine on days received"
label(inhosp_desc_df$halop_ever_int) <- "Received open-label haloperidol"
label(inhosp_desc_df$halop_days_exp_int) <-
  "Days received open-label haloperidol, if at all"
label(inhosp_desc_df$halop_total_exp_int) <-
  "Total dose of open-label haloperidol, if any"
label(inhosp_desc_df$halop_mean_exp_int) <-
  "Mean daily dose of open-label haloperidol on days received"
label(inhosp_desc_df$zipras_ever_int) <- "Received open-label ziprasidone"
label(inhosp_desc_df$zipras_days_exp_int) <-
  "Days received open-label ziprasidone, if at all"
label(inhosp_desc_df$zipras_total_exp_int) <-
  "Total dose of open-label ziprasidone, if any"
label(inhosp_desc_df$zipras_mean_exp_int) <-
  "Mean daily dose of open-label ziprasidone on days received"
label(inhosp_desc_df$antipsyc_ever_int) <- "Received open-label antipsychotics"
label(inhosp_desc_df$antipsyc_days_exp_int) <-
  "Days received open-label antipsychotics, if at all"
label(inhosp_desc_df$antipsyc_total_exp_int) <-
  "Total dose of open-label antipsychotics, if any"
label(inhosp_desc_df$antipsyc_mean_exp_int) <-
  "Mean daily dose of open-label antipsychotics on days received"
label(inhosp_desc_df$sofa_imp_max_int) <- "Highest daily SOFA"
label(inhosp_desc_df$sofa_imp_min_int) <- "Lowest daily SOFA"
label(inhosp_desc_df$sofa_imp_mean_int) <- "Mean daily SOFA"
label(inhosp_desc_df$ever_del_int) <- "Experienced delirium"
label(inhosp_desc_df$del_int_exp) <- "Days of delirium"
label(inhosp_desc_df$ever_hyperdel_int) <-
  "Experienced hyperactive delirium (RASS > 0)"
label(inhosp_desc_df$hyperdel_int_exp) <- "Days of hyperactive delirium"
label(inhosp_desc_df$ever_hypodel_int) <-
  "Experienced hypoactive delirium (RASS <= 0)"
label(inhosp_desc_df$hypodel_int_exp) <- "Days of hypoactive delirium"
label(inhosp_desc_df$ever_coma_int) <- "Experienced coma"
label(inhosp_desc_df$coma_int_exp) <- "Days of coma"
label(inhosp_desc_df$ever_delcoma_int) <- "Experienced delirium and/or coma"
label(inhosp_desc_df$delcoma_int_exp) <- "Days of delirium and/or coma"
label(inhosp_desc_df$dcfd_int) <-
  "Delirium/coma-free days (missing days imputed)"
label(inhosp_desc_df$icu_los) <-
  "Total length of ICU stay (entire hospitalization)"
label(inhosp_desc_df$event_icudis_90) <-
  "Successfully discharged from ICU within 90 days"
label(inhosp_desc_df$tte_icudis_90_exp) <-
  "Days to final successful ICU discharge within 90 days"
label(inhosp_desc_df$icu_readmit_number) <-
  "Number of ICU readmissions during hospitalization"
label(inhosp_desc_df$hosp_los) <- "Total length of hospitalization"
label(inhosp_desc_df$event_hospdis_90) <-
  "Successfully discharged from the hospital within 90 days"
label(inhosp_desc_df$tte_hospdis_90_exp) <-
  "Days to successful hospital discharge, if ever"
label(inhosp_desc_df$daysto_readm_exp) <-
  "Days to first ICU readmission, if ever"
label(inhosp_desc_df$dc_status) <- "Status at end of hospitalization"
label(inhosp_desc_df$hospdis_loc) <- "Hospital discharge location"
label(inhosp_desc_df$daysto_death_ih) <- "Days to death in hospital"
label(inhosp_desc_df$event_death_30) <- "Died within 30 days of randomization"
label(inhosp_desc_df$event_death_90) <- "Died within 90 days of randomization"

html(
  summaryM(
    as.formula(paste(paste(inhosp_vars, collapse = "+"), "trt", sep = " ~ ")),
    data = inhosp_desc_df,
    overall = TRUE
  ),
  exclude1 = FALSE, long = TRUE, digits = 2, what = "%", npct = "both",
  prmsd = TRUE, brmsd = TRUE, msdsize = mu$smaller2,
  middle.bold = TRUE, outer.size = mu$smaller2, rowsep = TRUE,
  caption = "Description of Intervention Period among Randomized Patients"
)
Description of Intervention Period among Randomized Patients.
N
Placebo
N=184
Haloperidol
N=192
Ziprasidone
N=190
Combined
N=566
Ever on mechanical ventilation (either type), entire hospitalization 566
    Yes 93% 172184 94% 181192 94% 178190 94% 531566
    No 7% 12184 6% 11192 6% 12190 6% 35566
Days on mechanical ventilation (either type), entire hospitalization 531 1.8 3.7 9.7
6.8 ±  8.3
1.2 3.7 8.0
10.5 ± 28.9
2.0 3.8 9.0
10.8 ± 22.3
1.8 3.7 8.9
9.4 ± 21.8
Times MV initiated (either type), entire hospitalization 566
    0 2% 4184 2% 3192 2% 4190 2% 11566
    1 66% 122184 66% 126192 63% 120190 65% 368566
    2 22% 41184 22% 43192 26% 49190 23% 133566
    3 5% 10184 7% 14192 6% 12190 6% 36566
    4 2% 3184 3% 5192 2% 3190 2% 11566
    5 2% 3184 1% 1192 1% 1190 1% 5566
    7 1% 1184 0% 0192 1% 1190 0% 2566
Number of intubations, entire hospitalization 566
    0 4% 7184 3% 6192 3% 5190 3% 18566
    1 79% 146184 79% 152192 81% 153190 80% 451566
    2 12% 23184 14% 26192 14% 26190 13% 75566
    3 3% 6184 3% 6192 3% 5190 3% 17566
    4 1% 2184 1% 1192 1% 1190 1% 4566
    5 0% 0184 1% 1192 0% 0190 0% 1566
Times NIPPV initiated, entire hospitalization 566
    0 79% 146184 80% 153192 76% 145190 78% 444566
    1 16% 29184 17% 32192 21% 40190 18% 101566
    2 4% 7184 3% 5192 2% 4190 3% 16566
    3 1% 1184 1% 2192 0% 0190 1% 3566
    4 1% 1184 0% 0192 0% 0190 0% 1566
    6 0% 0184 0% 0192 1% 1190 0% 1566
On MV at or within 24h of randomization 566
    Yes 93% 171184 93% 179192 93% 177190 93% 527566
    No 7% 13184 7% 13192 7% 13190 7% 39566
Ever successfully liberated from MV at randomization 524
    Yes 77% 130169 76% 135178 76% 135177 76% 400524
    No 23% 39169 24% 43178 24% 42177 24% 124524
Days to successful liberation from MV, entire hospitalization 400 1.1 2.7 4.9
4.4 ± 5.1
0.9 2.0 5.5
5.0 ± 9.3
1.5 2.7 4.6
4.5 ± 5.8
1.0 2.5 4.9
4.6 ± 7.0
Met criteria for sepsis on or before Intervention Day 18 565
    Yes 71% 130184 72% 138191 72% 137190 72% 405565
    No 29% 54184 28% 53191 28% 53190 28% 160565
Had a stroke during hospitalization 566
    Yes 5% 9184 2% 3192 3% 6190 3% 18566
    No 95% 175184 98% 189192 97% 184190 97% 548566
Received benzodiazepines 566
    Yes 61% 113184 61% 117192 63% 120190 62% 350566
    No 39% 71184 39% 75192 37% 70190 38% 216566
Days received benzodiazepines, if at all 350 1.0 2.0 5.0
3.7 ± 3.4
1.0 2.0 5.0
3.6 ± 3.2
1.0 2.0 5.0
3.3 ± 2.8
1.0 2.0 5.0
3.5 ± 3.1
Total dose of benzodiazepines, if any 350 3.0 11.0 67.5
103.4 ± 275.0
5.2 11.5 53.8
88.9 ± 216.4
4.8 13.2 36.8
81.9 ± 241.2
4.0 12.2 53.9
91.2 ± 244.4
Mean daily dose of benzodiazepines on days received 350 2.4 4.3 13.5
16.8 ± 29.4
2.9 5.5 12.5
14.6 ± 25.2
2.5 5.0 10.8
15.3 ± 27.2
2.5 5.0 12.5
15.5 ± 27.2
Received opioids 566
    Yes 90% 165184 92% 176192 91% 172190 91% 513566
    No 10% 19184 8% 16192 9% 18190 9% 53566
Days received opioids, if at all 513 3.0 6.0 9.0
6.4 ± 4.0
2.0 5.0 9.0
6.1 ± 4.1
2.0 4.5 9.0
5.6 ± 4.0
2.0 5.0 9.0
6.0 ± 4.1
Total dose of opioids, if any 513 1000 3390 9400
17714 ± 112680
1056 3153 8479
8250 ±  13391
730 2877 8621
8682 ±  16426
915 3067 9009
11439 ±  65093
Mean daily dose of opioids on days received 513 233 676 1515
5530 ± 56085
274 740 1468
1100 ±  1227
243 628 1574
1160 ±  1391
250 690 1514
2545 ± 31827
Received propofol 566
    Yes 64% 117184 52% 99192 58% 111190 58% 327566
    No 36% 67184 48% 93192 42% 79190 42% 239566
Days received propofol, if at all 327 1.0 2.0 4.0
3.1 ± 2.5
1.0 2.0 4.0
3.0 ± 2.5
1.0 2.0 4.0
2.8 ± 2.5
1.0 2.0 4.0
3.0 ± 2.5
Total dose of propofol, if any 327 878 2838 9251
7624 ± 12746
826 2498 7954
6382 ±  8598
602 1849 7404
6271 ± 11062
794 2487 8366
6788 ± 11032
Mean daily dose of propofol on days received 327 615 1391 2774
1878 ± 1708
623 1252 2313
1855 ± 2487
461 1080 2442
1570 ± 1548
576 1224 2512
1767 ± 1930
Received dexmedetomidine 566
    Yes 32% 59184 30% 58192 26% 49190 29% 166566
    No 68% 125184 70% 134192 74% 141190 71% 400566
Days received dexmedetomidine, if at all 166 2.0 3.0 3.5
2.8 ± 1.7
2.0 2.0 4.0
3.0 ± 2.2
2.0 3.0 4.0
3.2 ± 2.0
2.0 3.0 4.0
3.0 ± 2.0
Total dose of dexmedetomidine, if any 166 318 1285 3521
2730 ± 3735
530 1392 3449
2978 ± 4227
491 2068 3984
3027 ± 3627
347 1445 3565
2904 ± 3863
Mean daily dose of dexmedetomidine on days received 166 183 617 1100
767 ±  763
291 632 1132
804 ±  706
255 684 1163
823 ±  723
258 648 1143
796 ±  728
Received open-label haloperidol 566
    Yes 15% 28184 14% 27192 12% 23190 14% 78566
    No 85% 156184 86% 165192 88% 167190 86% 488566
Days received open-label haloperidol, if at all 78
    1 71% 2028 56% 1527 57% 1323 62% 4878
    2 7% 228 22% 627 17% 423 15% 1278
    3 11% 328 4% 127 4% 123 6% 578
    4 7% 228 11% 327 9% 223 9% 778
    5 0% 028 4% 127 9% 223 4% 378
    6 0% 028 4% 127 0% 023 1% 178
    7 4% 128 0% 027 0% 023 1% 178
    12 0% 028 0% 027 4% 123 1% 178
Total dose of open-label haloperidol, if any 78 2.0 4.5 7.8
8.9 ± 13.2
2.8 5.0 13.5
13.8 ± 20.3
2.2 5.0 11.0
19.2 ± 35.0
2.1 5.0 11.5
13.6 ± 23.8
Mean daily dose of open-label haloperidol on days received 78 2.0 2.8 5.5
4.5 ± 3.8
2.2 4.0 6.2
5.3 ± 4.2
2.0 3.5 5.6
5.3 ± 5.2
2.0 3.6 5.8
5.0 ± 4.3
Received open-label ziprasidone 566
    Yes 1% 2184 0% 0192 1% 1190 1% 3566
    No 99% 182184 100% 192192 99% 189190 99% 563566
Days received open-label ziprasidone, if at all 3
    1 0% 0 2 100% 1 1 33% 1 3
    2 50% 1 2 0% 0 1 33% 1 3
    5 50% 1 2 0% 0 1 33% 1 3
Total dose of open-label ziprasidone, if any 3
    80 50% 1 2 0% 0 1 33% 1 3
    150 0% 0 2 100% 1 1 33% 1 3
    180 50% 1 2 0% 0 1 33% 1 3
Mean daily dose of open-label ziprasidone on days received 3
    36 50% 1 2 0% 0 1 33% 1 3
    40 50% 1 2 0% 0 1 33% 1 3
    150 0% 0 2 100% 1 1 33% 1 3
Received open-label antipsychotics 566
    Yes 21% 38184 20% 39192 22% 41190 21% 118566
    No 79% 146184 80% 153192 78% 149190 79% 448566
Days received open-label antipsychotics, if at all 118 1.0 1.5 4.0
2.9 ± 2.6
1.0 2.0 6.0
3.6 ± 3.0
1.0 2.0 5.0
3.5 ± 3.5
1.0 2.0 5.0
3.3 ± 3.1
Total dose of open-label antipsychotics, if any 118 2.0 2.9 9.5
10.7 ± 17.9
2.7 6.0 14.5
14.4 ± 19.6
2.0 5.0 12.0
14.9 ± 29.7
2.0 5.0 12.0
13.4 ± 23.0
Mean daily dose of open-label antipsychotics on days received 118 1.2 2.0 3.6
3.2 ± 3.7
1.2 2.5 5.0
3.8 ± 4.0
1.0 2.0 4.7
3.4 ± 4.4
1.1 2.0 4.6
3.5 ± 4.0
Highest daily SOFA 566 8.0 11.0 14.0
11.3 ±  4.0
8.0 10.0 13.0
11.0 ±  3.8
8.0 11.0 14.0
11.3 ±  4.1
8.0 11.0 14.0
11.2 ±  4.0
Lowest daily SOFA 566 2.0 4.0 6.0
4.8 ± 4.0
2.0 4.0 6.0
4.8 ± 3.6
2.0 3.0 7.0
4.8 ± 3.9
2.0 4.0 6.0
4.8 ± 3.8
Mean daily SOFA 566 4.7 6.7 9.2
7.6 ± 4.0
4.8 6.3 9.4
7.4 ± 3.7
4.4 6.6 9.4
7.5 ± 3.8
4.6 6.6 9.4
7.5 ± 3.8
Experienced delirium 566
    Yes 100% 184184 100% 192192 100% 190190 100% 566566
    No 0% 0184 0% 0192 0% 0190 0% 0566
Days of delirium 566 2.0 4.0 8.0
5.3 ± 4.1
2.0 4.0 7.0
5.2 ± 3.8
2.0 4.0 6.0
4.8 ± 3.3
2.0 4.0 7.0
5.1 ± 3.7
Experienced hyperactive delirium (RASS > 0) 566
    Yes 36% 67184 39% 75192 35% 67190 37% 209566
    No 64% 117184 61% 117192 65% 123190 63% 357566
Days of hyperactive delirium 209
    1 48% 32 67 51% 38 75 60% 40 67 53% 110209
    2 27% 18 67 23% 17 75 18% 12 67 22% 47209
    3 13% 9 67 11% 8 75 3% 2 67 9% 19209
    4 7% 5 67 9% 7 75 13% 9 67 10% 21209
    5 1% 1 67 5% 4 75 1% 1 67 3% 6209
    6 3% 2 67 0% 0 75 1% 1 67 1% 3209
    7 0% 0 67 1% 1 75 1% 1 67 1% 2209
    8 0% 0 67 0% 0 75 1% 1 67 0% 1209
Experienced hypoactive delirium (RASS <= 0) 566
    Yes 99% 182184 98% 188192 99% 188190 99% 558566
    No 1% 2184 2% 4192 1% 2190 1% 8566
Days of hypoactive delirium 558 2.0 3.0 8.0
5.0 ± 3.9
2.0 4.0 6.0
4.8 ± 3.7
2.0 3.0 6.0
4.4 ± 3.1
2.0 3.5 6.0
4.8 ± 3.6
Experienced coma 566
    Yes 61% 112184 61% 118192 64% 121190 62% 351566
    No 39% 72184 39% 74192 36% 69190 38% 215566
Days of coma 351 1.0 2.0 4.0
2.9 ± 2.6
1.0 2.0 3.0
2.6 ± 2.2
1.0 2.0 4.0
3.0 ± 2.6
1.0 2.0 4.0
2.8 ± 2.5
Experienced delirium and/or coma 566
    Yes 100% 184184 100% 192192 100% 190190 100% 566566
    No 0% 0184 0% 0192 0% 0190 0% 0566
Days of delirium and/or coma 566 2.0 5.0 10.0
6.2 ±  4.5
3.0 5.0 8.0
5.9 ±  4.2
3.0 5.0 8.0
5.8 ±  3.9
3.0 5.0 9.0
6.0 ±  4.2
Delirium/coma-free days (missing days imputed) 566 0.0 7.0 11.2
6.3 ±  5.1
0.0 8.0 11.0
6.6 ±  4.9
2.0 8.0 11.0
6.8 ±  4.8
1.0 8.0 11.0
6.6 ±  4.9
Total length of ICU stay (entire hospitalization) 566 3.0 5.2 11.3
8.8 ±  8.4
3.0 5.1 11.0
9.5 ± 13.2
3.0 5.7 9.9
8.6 ±  9.5
3.0 5.3 11.0
9.0 ± 10.6
Successfully discharged from ICU within 90 days 566
    Yes 76% 140184 77% 148192 75% 142190 76% 430566
    No 24% 44184 23% 44192 25% 48190 24% 136566
Days to final successful ICU discharge within 90 days 430 3.0 5.2 13.6
9.7 ±  9.5
2.9 5.2 12.6
9.2 ± 10.0
2.9 5.2 9.7
8.8 ± 10.6
2.9 5.2 11.4
9.2 ± 10.0
Number of ICU readmissions during hospitalization 566
    0 88% 161184 86% 165192 91% 172190 88% 498566
    1 10% 18184 12% 23192 8% 15190 10% 56566
    2 2% 3184 2% 3192 2% 3190 2% 9566
    3 1% 2184 1% 1192 0% 0190 1% 3566
Days to first ICU readmission, if ever 68 1.1 3.5 7.6
5.6 ± 6.7
1.7 5.1 8.7
7.0 ± 9.6
1.6 5.2 9.4
7.4 ± 8.4
1.4 4.1 8.6
6.7 ± 8.3
Total length of hospitalization 566 7.0 11.6 21.3
16.1 ± 14.1
7.0 11.2 21.2
17.4 ± 21.6
6.3 11.3 20.9
16.8 ± 17.3
6.9 11.3 21.1
16.8 ± 18.0
Successfully discharged from the hospital within 90 days 566
    Yes 69% 127184 73% 140192 70% 133190 71% 400566
    No 31% 57184 27% 52192 30% 57190 29% 166566
Days to successful hospital discharge, if ever 400 8.4 12.9 23.1
17.1 ± 12.4
7.9 13.3 21.5
16.7 ± 13.1
7.9 11.6 21.2
15.9 ± 12.2
8.0 12.6 21.8
16.5 ± 12.6
Status at end of hospitalization 566
    Eligible for follow-up 69% 127184 75% 144192 69% 132190 71% 403566
    Died in hospital 29% 53184 23% 45192 28% 54190 27% 152566
    Withdrew in hospital 2% 4184 2% 3192 2% 4190 2% 11566
Hospital discharge location 411
    Home 36% 47129 45% 65146 46% 63136 43% 175411
    Assisted Living 0% 0129 1% 2146 0% 0136 0% 2411
    Inpatient Rehabilitation Facility 26% 33129 18% 26146 20% 27136 21% 86411
    Skilled Nursing Facility/Nursing Home 22% 28129 18% 27146 20% 27136 20% 82411
    Long-term acute care hospital (LTAC) or Long-term ventilatory facility 9% 11129 10% 14146 9% 12136 9% 37411
    Another Hospital 2% 3129 1% 1146 3% 4136 2% 8411
    Hospice facility 2% 3129 5% 7146 1% 2136 3% 12411
    Inpatient Psych 0% 0129 1% 2146 0% 0136 0% 2411
    Other 3% 4129 1% 2146 1% 1136 2% 7411
Days to death in hospital 152 3.9 9.3 15.7
13.8 ± 17.3
3.6 6.4 14.5
16.7 ± 34.5
4.7 8.3 17.3
15.3 ± 20.0
3.9 7.9 15.7
15.2 ± 24.3
Died within 30 days of randomization 566
    Yes 27% 50184 26% 50192 28% 53190 27% 153566
    No 73% 134184 74% 142192 72% 137190 73% 413566
Died within 90 days of randomization 566
    Yes 34% 63184 38% 73192 34% 65190 36% 201566
    No 66% 121184 62% 119192 66% 125190 64% 365566
a b c represent the lower quartile a, the median b, and the upper quartile c for continuous variables. x ± s represents X ± 1 SD.   N is the number of non-missing values.

Daily RASS Assessments

In response to reviewer queries, we describe all individual RASS assessments done by our research staff during the 14-day intervention period.

RASS Assessments during Intervention Phase.
N
Placebo
N=3333
Haloperidol
N=3394
Ziprasidone
N=3386
Combined
N=10113
RASS as performed by research staff 9425
    -5 6% 1923121 5% 1453153 5% 1563151 5% 4939425
    -4 7% 2093121 6% 1903153 9% 2713151 7% 6709425
    -3 13% 4053121 13% 3993153 13% 4033151 13% 12079425
    -2 13% 4073121 14% 4483153 12% 3823151 13% 12379425
    -1 13% 4133121 19% 5903153 14% 4543151 15% 14579425
    0 42% 13203121 37% 11733153 42% 13163151 40% 38099425
    1 4% 1183121 5% 1443153 4% 1163151 4% 3789425
    2 1% 423121 2% 513153 1% 413151 1% 1349425
    3 0% 143121 0% 133153 0% 103151 0% 379425
    4 0% 13121 0% 03153 0% 23151 0% 39425
N is the number of non-missing values.

Description of the Intervention


Once randomized, patients could receive study drug for treatment of delirium for up to 14 days, up to twice per day (with a third dose in rare cases). Study drug could be held temporarily, either for delirium resolution or for other reasons, or permanently discontinued. Table 8 describes randomization, receipt of study drug, reasons for study drug hold or discontinuation, and status at the end of hospitalization for each of the three treatment groups. Table 9 describes all opportunities to receive study drug dose.

In both tables, quantities are represented as either N (%) or as median [25th, 75th percentiles], followed by mean +/- standard deviation.

Note that temporary holds and permanent discontinuations listed below only include drug stopped for adverse clinical reasons; they do not include instances where study drug was not administered due to resolution of delirium or patient unavailability (including ICU discharge, death, study withdrawal, being off the floor, or being placed on comfort care measures/hospice).

Intervention by Patient

Patients were approximately equally randomized to the three treatment groups, with each group receiving study drug approximately the same number of days and times.

47% of randomized patients ever had study drug temporarily held, most commonly due to oversedation. There is a somewhat higher proportion of patients in the ziprasidone group who ever had study drug held, although the total number of doses of study drug given are similar between groups. Compared to the placebo and haloperidol groups, about 5% more patients randomized to ziprasidone ever had drug held due to prolonged QTc, and about 6% more had drug held at some point due to medical team refusal.

9% of randomized patients had the intervention permanently discontinued while actively receiving study drug (i.e., permanent discontinuation occurred at a scheduled dose immediately following a dose given, rather than temporarily held). This was most commonly due to refusal of either the medical team or the patient/family.

randtable_df <- rand_df %>%
  left_join(
    dplyr::select(ptstatus_df, id, randomized, died_inhosp, wd_inhosp, elig_fu),
    by = "id"
  ) %>%
  ## Add study drug info
  left_join(ptdrug_df, by = "id") %>%
  group_by(trt)

## Summarize variables that just need sums
rand_sums <- randtable_df %>%
  summarise_at(
    vars(randomized, ever_studydrug, ever_drug_held,
         matches("^ever\\_held\\_[a-z]+$"),
         ever_drug_permdc_active, matches("^permdc\\_active\\_[a-z]+$"),
         died_inhosp, wd_inhosp, elig_fu),
    funs(sum_na)
  )

## Summarize continuous variables
rand_cont <- randtable_df %>%
  summarise_at(
    vars(
      hrs_random_drug, num_drug_days, num_drug_doses, mean_drug_daily_ml,
      mean_drug_daily_mg, max_drug_dose_ml, max_drug_dose_mg,
      total_drug_dose_ml, total_drug_dose_mg
    ),
    funs(q25, q50, q75, "mean" = mean_na, "sd" = sd_na)
  )

## Recombine
rand_table <- left_join(rand_sums, rand_cont, by = "trt") %>%
  ## Calculate and create strings for table
  mutate(
    npct_studydrug = get_npct(ever_studydrug, randomized),
    npct_held = get_npct(ever_drug_held, ever_studydrug),
    npct_held_ae = get_npct(ever_held_ae, ever_studydrug),
    npct_held_dystonia = get_npct(ever_held_dystonia, ever_studydrug),
    npct_held_eps = get_npct(ever_held_eps, ever_studydrug),
    npct_held_other = get_npct(ever_held_other, ever_studydrug),
    npct_held_oversed = get_npct(ever_held_oversed, ever_studydrug),
    npct_held_refuseptfam = get_npct(ever_held_refuseptfam, ever_studydrug),
    npct_held_qtc = get_npct(ever_held_qtc, ever_studydrug),
    npct_held_refuseteam = get_npct(ever_held_refuseteam, ever_studydrug),
    npct_permdc_active = get_npct(ever_drug_permdc_active, ever_studydrug),
    npct_permdc_active_ae = get_npct(permdc_active_ae, ever_studydrug),
    npct_permdc_active_coma =
      get_npct(permdc_active_coma, ever_studydrug),
    npct_permdc_active_refuseteam =
      get_npct(permdc_active_refuseteam, ever_studydrug),
    npct_permdc_active_nms =
      get_npct(permdc_active_nms, ever_studydrug),
    npct_permdc_active_react =
      get_npct(permdc_active_react, ever_studydrug),
    npct_permdc_active_other =
      get_npct(permdc_active_other, ever_studydrug),
    npct_permdc_active_refuseptfam =
      get_npct(permdc_active_refuseptfam, ever_studydrug),
    npct_permdc_active_torsades =
      get_npct(permdc_active_torsades, ever_studydrug),
    npct_died = get_npct(died_inhosp, randomized),
    npct_wd = get_npct(wd_inhosp, randomized),
    npct_elig = get_npct(elig_fu, randomized),

    hrs_random_drug = describe_cont(
      hrs_random_drug_q50, hrs_random_drug_q25, hrs_random_drug_q75,
      hrs_random_drug_mean, hrs_random_drug_sd
    ),
    drug_days = describe_cont(
      num_drug_days_q50, num_drug_days_q25, num_drug_days_q75,
      num_drug_days_mean, num_drug_days_sd
    ),
    drug_doses = describe_cont(
      num_drug_doses_q50, num_drug_doses_q25, num_drug_doses_q75,
      num_drug_doses_mean, num_drug_doses_sd
    ),
    mean_drug_daily_ml = describe_cont(
      mean_drug_daily_ml_q50, mean_drug_daily_ml_q25, mean_drug_daily_ml_q75,
      mean_drug_daily_ml_mean, mean_drug_daily_ml_sd
    ),
    mean_drug_daily_mg = describe_cont(
      mean_drug_daily_mg_q50, mean_drug_daily_mg_q25, mean_drug_daily_mg_q75,
      mean_drug_daily_mg_mean, mean_drug_daily_mg_sd
    ),
    max_drug_dose_ml = describe_cont(
      max_drug_dose_ml_q50, max_drug_dose_ml_q25, max_drug_dose_ml_q75,
      max_drug_dose_ml_mean, max_drug_dose_ml_sd
    ),
    max_drug_dose_mg = describe_cont(
      max_drug_dose_mg_q50, max_drug_dose_mg_q25, max_drug_dose_mg_q75,
      max_drug_dose_mg_mean, max_drug_dose_mg_sd
    ),
    total_drug_dose_ml = describe_cont(
      total_drug_dose_ml_q50, total_drug_dose_ml_q25, total_drug_dose_ml_q75,
      total_drug_dose_ml_mean, total_drug_dose_ml_sd
    ),
    total_drug_dose_mg = describe_cont(
      total_drug_dose_mg_q50, total_drug_dose_mg_q25, total_drug_dose_mg_q75,
      total_drug_dose_mg_mean, total_drug_dose_mg_sd
    )
  ) %>%
  ## Remove all NAs (result of placebo group)
  mutate_at(
    vars(matches("\\_mg$")),
    ~ ifelse(
      gsub(" +", " ", .) == "NA [NA, NA]\\\n NaN +/- NA",
      "[no values]",
      .
    )
  ) %>%
  dplyr::select(
    trt, randomized, npct_studydrug, hrs_random_drug, drug_days, drug_doses,
    ends_with("_ml"), ends_with("_mg"),
    npct_held, matches("^npct\\_held\\_"), npct_permdc_active,
    matches("^npct\\_permdc\\_active\\_"), npct_died, npct_wd, npct_elig
  ) %>%
  gather(key = table_row, value = table_string, -trt) %>%
  spread(key = trt, value = table_string) %>%
  mutate(
    sort_order = case_when(
      table_row == "randomized" ~ 1,
      table_row == "npct_studydrug" ~ 2,
      table_row == "hrs_random_drug" ~ 3,
      table_row == "drug_days" ~ 4,
      table_row == "drug_doses" ~ 5,
      table_row == "mean_drug_daily_ml" ~ 6,
      table_row == "max_drug_dose_ml" ~ 7,
      table_row == "total_drug_dose_ml" ~ 8,
      table_row == "mean_drug_daily_mg" ~ 9,
      table_row == "max_drug_dose_mg" ~ 10,
      table_row == "total_drug_dose_mg" ~ 11,
      table_row == "npct_held" ~ 12,
      table_row == "npct_permdc_active" ~ 13,
      table_row == "npct_died" ~ 14,
      table_row == "npct_wd" ~ 15,
      table_row == "npct_elig" ~ 16,
      grepl("^npct\\_held\\_", table_row) ~ 17,
      grepl("^npct\\_permdc\\_", table_row) ~ 18,
      TRUE ~ 19
    ),
    table_row = case_when(
      table_row == "randomized"              ~ "Randomized",
      table_row == "npct_studydrug"          ~ "Received >=1 dose study drug",
      table_row == "hrs_random_drug"         ~ "Hours between randomization and first dose given",
      table_row == "drug_days"               ~ "Days received study drug",
      table_row == "drug_doses"              ~ "Doses of study drug",
      table_row == "mean_drug_daily_ml"      ~ "Mean daily dose of study drug (mL)",
      table_row == "mean_drug_daily_mg"      ~ "Mean daily dose of study drug (mg)",
      table_row == "max_drug_dose_ml"        ~ "Maximum daily dose (ml)",
      table_row == "max_drug_dose_mg"        ~ "Maximum daily dose (mg)",
      table_row == "total_drug_dose_ml"      ~ "Total drug given (ml)",
      table_row == "total_drug_dose_mg"      ~ "Total drug given (mg)",
      table_row == "npct_held"               ~ "Ever had study drug temporarily held",
      table_row == "npct_permdc_active"      ~ "Had active study drug permanently discontinued",
      table_row == "npct_died"               ~ "Died in the hospital",
      table_row == "npct_wd"                 ~ "Withdrew from study in the hospital",
      table_row == "npct_elig"               ~ "Eligible for long-term follow-up",
      table_row == "npct_held_ae"            ~ "Adverse event",
      table_row == "npct_held_dystonia"      ~ "Dystonia",
      table_row == "npct_held_eps"           ~ "Extrapyramidal symptoms",
      table_row == "npct_held_other"         ~ "Other reason",
      table_row == "npct_held_oversed"       ~ "Oversedation",
      table_row == "npct_held_qtc"           ~ "Prolonged QTc",
      table_row == "npct_held_refuseptfam"   ~ "Patient/family refusal",
      table_row == "npct_held_refuseteam"    ~ "Medical team refusal",
      table_row == "npct_permdc_active_ae"   ~ "Adverse event",
      table_row == "npct_permdc_active_coma" ~
        "Coma due to structural brain damage",
      table_row == "npct_permdc_active_nms"         ~ "Suspected NMS",
      table_row == "npct_permdc_active_other"       ~ "Other reason",
      table_row == "npct_permdc_active_react"       ~ "DRESS",
      table_row == "npct_permdc_active_refuseptfam" ~ "Patient/family refusal",
      table_row == "npct_permdc_active_refuseteam"  ~ "Medical team refusal",
      table_row == "npct_permdc_active_torsades"    ~ "Torsades de pointes",
      TRUE ~ "")
  ) %>%
  arrange(sort_order) %>%
  dplyr::select(-sort_order)
Placebo Haloperidol Ziprasidone
Randomized 184 192 190
Randomized Patients
Received >=1 dose study drug 183 (99%) 192 (100%) 189 (99%)
Hours between randomization and first dose given 1 [1, 2]
2.60 +/- 8.73
1 [1, 2]
1.84 +/- 4.21
1 [1, 2]
2.01 +/- 1.98
Days received study drug 4 [3, 7]
5.49 +/- 3.91
4 [3, 6]
5.01 +/- 3.59
4 [3, 7]
4.96 +/- 3.48
Doses of study drug 7 [5, 13]
9.96 +/- 7.66
7 [4, 12]
9.05 +/- 7.11
7 [4, 12]
8.78 +/- 6.59
Mean daily dose of study drug (mL) 2 [2, 3]
2.20 +/- 1.02
2 [2, 3]
2.20 +/- 0.96
2 [1, 3]
1.99 +/- 0.94
Maximum daily dose (ml) 2 [2, 2]
1.70 +/- 0.57
2 [2, 2]
1.75 +/- 0.54
2 [1, 2]
1.67 +/- 0.58
Total drug given (ml) 9 [4, 20]
14.32 +/- 14.50
8 [4, 18]
13.07 +/- 13.25
8 [4, 15]
11.38 +/- 11.63
Mean daily dose of study drug (mg) [no values] 11 [ 8, 15]
10.99 +/- 4.82
20 [13, 28]
19.95 +/- 9.44
Maximum daily dose (mg) [no values] 10 [10, 10]
8.73 +/- 2.72
20 [10, 20]
16.71 +/- 5.84
Total drug given (mg) [no values] 42 [19, 88]
65.33 +/- 66.27
75 [35, 150]
113.76 +/- 116.26
Ever had study drug temporarily held 81 (44%) 85 (44%) 101 (53%)
Had active study drug permanently discontinued 18 (10%) 15 (8%) 20 (11%)
Died in the hospital 53 (29%) 45 (23%) 54 (28%)
Withdrew from study in the hospital 5 (3%) 3 (2%) 7 (4%)
Eligible for long-term follow-up 127 (69%) 144 (75%) 132 (69%)
Reasons Study Drug Temporarily Held (% of Patients Who Received Study Drug)
Adverse event 1 (1%) 5 (3%) 3 (2%)
Dystonia 0 (0%) 1 (1%) 0 (0%)
Extrapyramidal symptoms 1 (1%) 1 (1%) 1 (1%)
Other reason 25 (14%) 19 (10%) 24 (13%)
Oversedation 46 (25%) 42 (22%) 50 (26%)
Prolonged QTc 10 (5%) 13 (7%) 20 (11%)
Patient/family refusal 3 (2%) 6 (3%) 5 (3%)
Medical team refusal 15 (8%) 17 (9%) 29 (15%)
Reasons Active Study Drug Permanently Discontinued (% of Patients Who Received Study Drug)
Adverse event 0 (0%) 2 (1%) 2 (1%)
Coma due to structural brain damage 2 (1%) 0 (0%) 0 (0%)
Suspected NMS 0 (0%) 0 (0%) 0 (0%)
Other reason 2 (1%) 1 (1%) 1 (1%)
DRESS 0 (0%) 0 (0%) 0 (0%)
Patient/family refusal 7 (4%) 8 (4%) 7 (4%)
Medical team refusal 7 (4%) 4 (2%) 10 (5%)
Torsades de pointes 0 (0%) 0 (0%) 0 (0%)

Intervention by Dose

Table 9 describes the 6,355 doses of study drug attempted during the course of the study - generally, two doses per day that the patient remained alive and in the ICU. This includes:

  1. Doses given
  2. Doses temporarily held for adverse clinical reasons
  3. Doses permanently discontinued for adverse clinical reasons while the patient was actively receiving study drug (ie: A patient who was actively receiving drug until discontinuation due to suspected NMS would be counted below; a patient who had had drug held for two days due to oversedation, then had study drug permanently discontinued by request of their family, would not be included)

We do not include below instances where study drug was not administered due to resolution of delirium or patient unavailability (including ICU discharge, death, study withdrawal, being off the floor, or being placed on comfort care measures/hospice).

Nearly all randomized patients received at least one dose of study drug. Two patients had study drug held due to either oversedation or prolonged QTc during their remaining ICU stay, and never received a dose of study drug.

About 75% of doses were successfully given in each of the three treatment groups. Pre-dose QTcs (indicated by 12-lead ECG if available, and telemetry otherwise) were also roughly equivalent between the three groups.

Oversedation was the most common reason for temporary hold by far, followed distantly by medical team refusal and prolonged QTc. Temporary study drug hold due to other safety concerns (adverse events, dystonia, EPS) was rare.

dose_table <- dose_attempts %>%
  mutate(
    ## Indicator for whether dose was held d/t oversedation, but no actual RASS
    rass_na = held_oversed & is.na(oversed_actual),
    ## Create "final" QTc: 12-lead ECG if available, otherwise telemetry
    ecg_result = as.numeric(ecg_result),
    pre_qtc_final = if_else(!is.na(ecg_result), ecg_result, pre_dose_qtc),
    ## Indicator for whether pre-dose QTc > 500
    pre_qtc_500 = if_else(pre_qtc_final > 500, TRUE, FALSE)
  ) %>%
  group_by(trt) %>%
  summarise(
    doses_trt = n(), ## Total doses per treatment
    doses_given = sum_na(drug_given),
    doses_held = sum_na(drug_held),
    doses_permdc = sum_na(drug_permdc),
    type_initial = sum_na(dose_type == "Initial Starting Dose"),
    type_restart = sum_na(dose_type == "Restarting Dose"),
    type_increase = sum_na(dose_type == "Increased Dose"),
    type_decrease = sum_na(dose_type == "Decreased Dose (CAM-ICU Negative)"),
    type_maintmax = sum_na(dose_type == "Maintained at Maximum Dose"),
    type_maint = sum_na(
      dose_type == "Maintained (at current dose for medically induced coma)"
    ),
    type_other = sum_na(dose_type == "Other"),
    ml_025 = sum_na(dose_ml == 0.25),
    ml_050 = sum_na(dose_ml == 0.50),
    ml_100 = sum_na(dose_ml == 1.00),
    ml_200 = sum_na(dose_ml == 2.00),
    q25_preqtc = q25(pre_qtc_final),
    q50_preqtc = q50(pre_qtc_final),
    q75_preqtc = q75(pre_qtc_final),
    mean_preqtc = mean_na(pre_qtc_final),
    sd_preqtc = sd_na(pre_qtc_final),
    pre_qtc_500 = sum_na(pre_qtc_500),
    held_qtc = sum_na(held_qtc),
    held_oversed = sum_na(held_oversed),
    rass_0 = sum_na(oversed_actual == "0"),
    rass_1 = sum_na(oversed_actual == "-1"),
    rass_2 = sum_na(oversed_actual == "-2"),
    rass_3 = sum_na(oversed_actual == "-3"),
    rass_4 = sum_na(oversed_actual == "-4"),
    rass_5 = sum_na(oversed_actual == "-5"),
    rass_na = sum_na(rass_na),
    held_eps = sum_na(held_eps),
    held_dystonia = sum_na(held_dystonia),
    held_ae = sum_na(held_ae),
    held_refuseteam = sum_na(held_refuseteam),
    held_refuseptfam = sum_na(held_refuseptfam),
    held_other = sum_na(held_other),
    permdc_nms = sum_na(permdc_nms),
    permdc_react = sum_na(permdc_react),
    permdc_torsades = sum_na(permdc_torsades),
    permdc_coma = sum_na(permdc_coma),
    permdc_ae = sum_na(permdc_ae),
    permdc_refuseptfam = sum_na(permdc_refuseptfam),
    permdc_refuseteam = sum_na(permdc_refuseteam),
    permdc_other = sum_na(permdc_other)
  ) %>%
  ## -- Turn into a table ------------------------------------------------------
  ## Doses given
  mutate_at(
    vars(type_initial:ml_200), funs(get_npct(., denom = doses_given))
  ) %>%
  ## QTc: doses given + held
  mutate(
    desc_preqtc = describe_cont(
      q50_preqtc, q25_preqtc, q75_preqtc, mean_preqtc, sd_preqtc
    ),
    pre_qtc_500 = get_npct(pre_qtc_500, denom = doses_given)
  ) %>%
  ## Doses temporarily held
  mutate_at(
    vars(rass_0:rass_na), funs(get_npct(., denom = held_oversed))
  ) %>%
  mutate_at(
    vars(held_qtc, held_oversed, held_eps:held_other),
    funs(get_npct(., denom = doses_trt))
  ) %>%
  ## Doses permanently discontinued
  mutate_at(
    vars(permdc_nms:permdc_other), funs(get_npct(., denom = doses_trt))
  ) %>%
  ## Do these last because we need the numeric versions for denominators
  ## (No longer true if we use all dose attempts as denominators, but keeping
  ## comment in case we switch back)
  mutate_at(
    vars(doses_given, doses_held, doses_permdc),
    funs(get_npct(., denom = doses_trt))
  ) %>%
  ## Transpose to one row per descriptor, with a column for each treatment group
  dplyr::select(
    trt, doses_trt, doses_given:doses_permdc, type_initial:ml_200,
    desc_preqtc, pre_qtc_500, held_qtc:held_other, rass_0:rass_5,
    permdc_nms:permdc_other
  ) %>%
  gather(key = table_row, value = dose_value, -trt) %>%
  spread(key = trt, value = dose_value) %>%
  ## Remove permanent discontinuation rows
  filter(!grepl("^permdc", table_row)) %>%
  ## Table formatting
  mutate(
    sort_order = case_when(
      table_row == "doses_trt" ~ 1,
      table_row == "doses_given" ~ 2,
      table_row == "doses_held" ~ 3,
      table_row == "doses_permdc" ~ 4,
      table_row == "ml_025" ~ 5,
      table_row == "ml_050" ~ 6,
      table_row == "ml_100" ~ 7,
      table_row == "ml_200" ~ 8,
      table_row == "type_initial" ~ 9,
      table_row == "type_restart" ~ 10,
      table_row == "type_decrease" ~ 11,
      table_row == "type_increase" ~ 12,
      table_row == "type_maint" ~ 13,
      table_row == "type_maintmax" ~ 14,
      table_row == "type_other" ~ 15,
      table_row == "desc_preqtc" ~ 16,
      table_row == "pre_qtc_500" ~ 17,
      table_row == "held_ae" ~ 18,
      table_row == "held_dystonia" ~ 19,
      table_row == "held_eps" ~ 20,
      table_row == "held_oversed" ~ 21,
      table_row == "held_qtc" ~ 22,
      table_row == "held_refuseptfam" ~ 23,
      table_row == "held_refuseteam" ~ 24,
      table_row == "held_other" ~ 25,
      table_row %in% paste0("rass_", 0:5) ~ 26,
      table_row == "permdc_ae" ~ 27,
      table_row == "permdc_coma" ~ 28,
      table_row == "permdc_nms" ~ 29,
      table_row == "permdc_react" ~ 30,
      table_row == "permdc_torsades" ~ 31,
      table_row == "permdc_refuseptfam" ~ 32,
      table_row == "permdc_refuseteam" ~ 33,
      table_row == "permdc_other" ~ 34,
      TRUE ~ 37
    ),
    table_row = case_when(
      table_row == "doses_trt" ~ "Dose Opportunities",
      table_row == "doses_given" ~ "Given",
      table_row == "doses_held" ~ "Temporarily held",
      table_row == "doses_permdc" ~
        "Permanently discontinued from active study drug",
      table_row == "ml_025" ~ "0.25 mL",
      table_row == "ml_050" ~ "0.50 mL",
      table_row == "ml_100" ~ "1.00 mL",
      table_row == "ml_200" ~ "2.00 mL",
      table_row == "type_initial" ~ "Initial starting dose",
      table_row == "type_restart" ~ "Restarting dose",
      table_row == "type_decrease" ~ "Decrease (CAM-ICU negative)",
      table_row == "type_increase" ~ "Increase",
      table_row == "type_maint" ~ "Maintained (med. induced coma)",
      table_row == "type_maintmax" ~ "Maintained at max dose",
      table_row == "type_other" ~ "Other",
      table_row == "desc_preqtc" ~
        "Pre-dose QTc (12-lead ECG if available; telemetry otherwise)",
      table_row == "pre_qtc_500" ~ "Pre-dose QTc > 500",
      table_row == "held_ae" ~ "Adverse event",
      table_row == "held_dystonia" ~ "Dystonia",
      table_row == "held_eps" ~ "Extrapyramidal symptoms",
      table_row == "held_oversed" ~ "Oversedation",
      table_row == "held_qtc" ~ "Prolonged QTc",
      table_row == "held_refuseptfam" ~ "Patient/family refusal",
      table_row == "held_refuseteam" ~ "Medical team refusal",
      table_row == "held_other" ~ "Other",
      table_row == "rass_na" ~ "Not documented",
      table_row == "rass_0" ~ "0",
      table_row %in% paste0("rass_", 1:5) ~
        paste0("-", gsub("^rass\\_", "", table_row)),
      table_row == "permdc_ae" ~ "Adverse event",
      table_row == "permdc_coma" ~ "Coma due to structural brain damage",
      table_row == "permdc_nms" ~ "Suspected NMS",
      table_row == "permdc_react" ~ "DRESS",
      table_row == "permdc_torsades" ~ "Torsades de pointes",
      table_row == "permdc_refuseptfam" ~ "Patient/family refusal",
      table_row == "permdc_refuseteam" ~ "Medical team refusal",
      table_row == "permdc_other" ~ "Other",
      TRUE ~ "fix this!"
    )
  ) %>%
  arrange(sort_order) %>%
  dplyr::select(-sort_order)
Placebo Haloperidol Ziprasidone
Dose Opportunities 2195 2073 2087
All Dose Opportunities
Given 1832 (83%) 1737 (84%) 1668 (80%)
Temporarily held 345 (16%) 321 (15%) 399 (19%)
Permanently discontinued from active study drug 18 (1%) 15 (1%) 20 (1%)
Doses Given (% of All Opportunities)
0.25 mL 153 (8%) 97 (6%) 190 (11%)
0.50 mL 287 (16%) 291 (17%) 345 (21%)
1.00 mL 346 (19%) 363 (21%) 336 (20%)
2.00 mL 1046 (57%) 988 (57%) 797 (48%)
Initial starting dose 185 (10%) 194 (11%) 193 (12%)
Restarting dose 47 (3%) 47 (3%) 66 (4%)
Decrease (CAM-ICU negative) 166 (9%) 156 (9%) 186 (11%)
Increase 351 (19%) 371 (21%) 367 (22%)
Maintained (med. induced coma) 29 (2%) 27 (2%) 34 (2%)
Maintained at max dose 1053 (57%) 939 (54%) 817 (49%)
Other 1 (0%) 5 (0%) 3 (0%)
Pre-dose QTc (12-lead ECG if available; telemetry otherwise) 440 [410, 468]
436.22 +/- 46.32
436 [406, 466]
432.90 +/- 48.52
442 [412, 468]
437.01 +/- 44.72
Pre-dose QTc > 500 98 (5%) 92 (5%) 61 (4%)
Doses Temporarily Held (% of All Opportunities)
Adverse event 1 (0%) 5 (0%) 4 (0%)
Dystonia 0 (0%) 1 (0%) 0 (0%)
Extrapyramidal symptoms 4 (0%) 1 (0%) 1 (0%)
Oversedation 241 (11%) 228 (11%) 258 (12%)
Prolonged QTc 21 (1%) 18 (1%) 44 (2%)
Patient/family refusal 3 (0%) 11 (1%) 5 (0%)
Medical team refusal 48 (2%) 37 (2%) 58 (3%)
Other 27 (1%) 20 (1%) 29 (1%)
Actual RASS for Doses Held due to Oversedation
0 2 (1%) 3 (1%) 7 (3%)
-1 1 (0%) 0 (0%) 0 (0%)
-2 56 (23%) 63 (28%) 61 (24%)
-3 49 (20%) 54 (24%) 69 (27%)
-4 61 (25%) 53 (23%) 80 (31%)
-5 25 (10%) 49 (21%) 34 (13%)
Not documented 47 (20%) 6 (3%) 7 (3%)

“Other” Reasons for Hold & Discontinuation

Explanations for study drug held (Table 10) and discontinued (Table 11) for “other” reasons are listed in the tables below. (To save space, these tables are collapsed. These explanations are taken directly from our database; potentially identifiable information, including dates, times and parenthetical details, have been redacted to preserve patient privacy.)

Table 10: Reasons for Temporary Study Drug Hold due to ‘Other’

“Other” Reasons Study Drug Held

Explanation for ‘other’ study drug hold
Held for safety check with Wes on CT results
Subject did not have a line. xxpm phlebotomy did not come up until xxpm, so we called VCC and were advised to just give a xxpm dose and resume the following day.
first dose adminstered at xx/xx/xx
not randomized yet
Erronously held for QTC xx/xx/xx-See NTF
First dose after enrollment given xx/xx/xx needed at least 12 hours before second dose.
First dose was given later in the evening, second dose was not given in day 0, but spaced out appropriate 12 hour before next dose
Patient randomized late in the day, second dose could not occur until the following date. 3 doses are noted on Interventional Day 1.
initial dose was given at xx/xx/xx so no second daily dose was given
First dose was given at xx/xx/xx that day and RC failed to order a second dose to be given at least six hours later. Next dose given was the following day at xx/xx/xx.
Patient randomized past xxpm, did not receive second dose of study med until the following day. Second dose annotated on Interventional Day 1.
Patient received second study drug dosage on the following day, as randomization and starting drug dose were at xx/xx/xx and xx/xx/xx respectively. Second dose is note on Interventional Day 1.
Patient’s starting dose was given at xx/xx/xx, so the second dose was not given till the following day. Noted as receiving 3 doses on interventional day 1.
Second dose given on xx/xx/xxam schedule
Pt. was scheduled to receive 2nd dose the following morning
N/A afternoon enrollment, second dose given next day xx/xx/xx
Enrolled at xx/xx/xx
xx/xx/xx and xx/xx/xx dosing started due to proximity to xx/xx/xx of first dose.
See NTF.
Patient did not receive initial dose on time. Held p.m. dose to allow for 6+ hours between doses
see Note to File
unintetionally missed. Spoke with L. Boehm and the second dose should have been given 12 hrs after initial dose and then start with the xxam % xxpm dosing the following day.Note to file written
Was not ordered.
first dose was given at late wevening after the consent was obtained
The first CAM and RASS wasdone at xx/xx/xx after cosent .
Pt was comatose and prior tothis had 4 CAM negs/ as per the SOP no drug given/ Addendum by Project Manager: Patient was RASS -4 and study drug was maintained which meant drug kept at 0.
Pt had received the evening dose of xx/xx/xx @ xxam today( please see note to file) too early for the am dose.
Please see note to file. Study drug never restarted.
First dose given late in Evening.
First dose was given at xx/xx/xx PM
Following dose accurately administered on xx/xx/xx as documented
Patient was enrolled in the evening; first dose was evening dose
Starting dose administered late at night; subsuqent dose properly administered the following day as seen in Day 1 data
Nurse did not administer d/t uncertainty of protocol and care team starting pt. on Haldol & instructions -see NTF
Patient readmitted to ICU but PAD was not completed dut to patient being in procedure
Study drug given late on xx/xx/xx
Study Coordinator failed to locate PI to order the study drug
First dose of the study drug given at xx/xx/xx. Next dose was scheduled for next day at xx/xx/xx
delirium resolved, but also UTA because pt in OR
Pt got 1st dose of study drug at xx/xx/xx. Per protocol, 2cnd dose was given 6 hours later–RN gave on xx/xx/xx
Nurse did not give. She was unable to scan medication
Dose #1 given xx/xx/xx
Patient randomized late in day, received first dose at xx/xx/xx, next dose not due until xx/xx/xx.
drug stopped 1 day early due to misunderstanding of duration of interventional phase
drug stopped 1 day early due to misunderstanding of duration of interventional phase
pt. should have received the next dose 6 hrs later, see NTF
Due to the lateness of the randomization, and uncertainty about when the drug would be available, the decision was made to not give the next dose 6hrs later. This allowed the following day’s dosing schedule to stay at xx/xx/xx and xx/xx/xx.
Orders were not written for dose, coordinator not notified.
miscommunication, see NTF
not ordered by mistake
ICU team decided to paralyze the patient secondary to an acute phase of respiratory acidosis and high peak pressures on the ventilator. Protocol says to maintain at current dose when intentionally in coma and patient was not on any study drug on the prior day.
Study drug was not documented on the MAR. Nurse was not aware to give. See NTF.
The patient moved to a different room. Night dose was stored under the previous room number and nurse thought there was no drug for the night dose. Drug was not given.
Study drug was not given due to RN unable to assess the QTc prior to study drug administration. Pt had bigeminy/afib all afternoon/evening
Study drug was not given due to RN unable to assess the QTc prior to study drug administration. Pt had bigeminy/afib all afternoon/evening
RN did not administer medication stating she could not find it. Drug wasted by AM RN w/ coordinator present.
Nurse was confused about the protocol and thought that if it was over an hour late that it shouldn’t be given. Pt was getting a procedure.
Dose set to be given in the evening was given in the morning, deleting the prompt for the night RN to give an evening dose
Patient enrolled late, and only received xxPM Dose.
Automated Order Entry System Failure
it was erroneously held b/c the nurse miscalculated the Qtc. “See NTF”.
Nurse stated that drug was not received
Bedside nurse noted that in report the night nurse stated that she asked pharmacy for drug multiple times but did not receive drug so did not give it. No page was received, and nurse was called by study staff prior to scheduled drug delivery and was asked to page with any questions and did not.
see NTF - error related to protocol non-compliance
unknown reason/missing data found in dataclean. Per chart review, no dose given this day.
Not Enrolled in the study
Order disappeared from system and pharmacy did not dispense it due to this
Pharmacy Error
Study drug administered following day as documented on post int. day 1
first dose was given at xx/xx/xx
RN negligence
RN negligence
RN did not give drug
acute change in mental status
2nd dose would’ve been given under 6 hours.
second dose would’v been after midnight; resumed drug admin xxam/xxpm following day
Table 11: Reasons for Study Drug Discontinuation due to ‘Other’

“Other” Reasons Study Drug Permanently Discontinued

Explanation for ‘other’ study drug discontinuation
Was d/c in error- see NTF
Was d/c in error-See NTF
study drug was discontinued and isnt refelected for this day due to the redcap datashift
study drug was discontinued and isnt refelected for this day due to the redcap datashift
Data shift - originally thought to be at end of drug schedule
Data shift - originally thought to be at end of drug schedule
Confusion r/t duration of study phases, drug should have been given.
Confusion r/t duration of study phases, drug should have been given.

Description of Temporary Holds

We describe, for each time study drug was temporarily held, the number of doses for which it was held and whether study drug was ultimately restarted, or not restarted for one of several reasons.

tempholds_df <- tempholds_df %>%
  left_join(rand_df, by = "id")

tempholds_trt <- tempholds_df %>%
  count(trt)

tempholds_doses <- tempholds_df %>%
  group_by(trt) %>%
  summarise_at(
    vars(doses_held),
    funs(p25 = q25, p50 = q50, p75 = q75, mean = mean_na, sd = sd_na)
  ) %>%
  mutate(describe_holds = describe_cont(p50, p25, p75, mean, sd)) %>%
  dplyr::select(trt, describe_holds) %>%
  spread(key = trt, value = describe_holds) %>%
  mutate(reason = "Number of doses held")

tempholds_reasons <- tempholds_df %>%
  count(trt, drug_restarted) %>%
  left_join(tempholds_trt, by = "trt") %>%
  set_names(c("trt", "reason", "n_reason", "n_trt")) %>%
  mutate(npct = get_npct(n_reason, n_trt)) %>%
  dplyr::select(trt, reason, npct) %>%
  spread(key = trt, value = npct)

tempholds_info <- bind_rows(
  tempholds_trt %>%
    spread(key = trt, value = n) %>%
    mutate(reason = "Total temporary holds") %>%
    mutate_at(vars("Placebo", "Haloperidol", "Ziprasidone"), ~ as.character(.)),
  tempholds_doses,
  tempholds_reasons
) %>%
  dplyr::select(reason, Placebo, Haloperidol, Ziprasidone) %>%
  mutate(
    sort_order = case_when(
      reason == "Total temporary holds"      ~ 0,
      reason == "Number of doses held"       ~ 1,
      reason == "Restarted"                  ~ 2,
      reason == "Not restarted"              ~ 3,
      reason == "Dlr resolved/ICU discharge" ~ 4,
      reason == "Permanently discontinued"   ~ 5,
      TRUE                                   ~ 6
    )
  ) %>%
  arrange(sort_order) %>%
  dplyr::select(-sort_order)

tempholds_info %>%
  kable(
    format = "html",
    col.names = c("", "Placebo", "Haloperidol", "Ziprasidone"),
    align = c("l", rep("r", 3))
  ) %>%
  mykablestyle() %>%
  group_rows("Was drug restarted?", 3, 7)
Placebo Haloperidol Ziprasidone
Total temporary holds 115 112 142
Number of doses held 1 [1, 3]
3.00 +/- 3.72
1 [1, 3]
2.88 +/- 3.62
1 [1, 3]
2.81 +/- 3.96
Was drug restarted?
Restarted 75 (65%) 68 (61%) 88 (62%)
Not restarted 18 (16%) 15 (13%) 17 (12%)
Dlr resolved/ICU discharge 15 (13%) 12 (11%) 26 (18%)
Permanently discontinued 6 (5%) 13 (12%) 8 (6%)
[n/a; only last dose held] 1 (1%) 4 (4%) 3 (2%)

Holds/Discontinuations due to Adverse Events

As noted above, during the intervention, 10 study drug doses were documented as temporarily held due to an adverse event, and 4 doses were documented as permanently discontinued due to an adverse event. The following table describes these 14 scenarios, as manually investigated by our clinical staff. Potentially identifiable information, including dates, times and parenthetical details, is redacted.

The final column indicates whether the adverse event documentation reflects any potential data entry issues. Our database was locked prior to breaking the treatment blind; therefore, any errors discovered after that point have not been corrected in the original data.

Protocol Noncompliance

We summarize below any protocol noncompliance that increased safety risk to the patient, broken down according to a simple categorization scheme followed prospectively during the conduct of the MIND-USA investigation. During the entire study, there were 75 events which met these criteria, among 67 unique patients. Nearly all events were lack of completion/documentation of study assessments, study drug titration which did not follow the protocol, or “other.” Study drug titration noncompliance happened most frequently in the haloperidol and ziprasidone groups; study assessment noncompliance happened most frequently in the placebo group.

## -- Summarize protocol noncompliance: N (%) in each category -----------------
## Variables indicating categories for noncompliance
noncomp_cats <-
  names(noncompliance_df)[grepl("^ntf\\_cat\\_", names(noncompliance_df))]

## Set treatment group to "Not randomized" for noncompliance events among
## patients consented but disqualified
noncompliance_df <- noncompliance_df %>%
  mutate(trt = ifelse(is.na(trt), "Not randomized", trt))

## How many noncompliance events in each treatment group?
noncomp_bytrt <- noncompliance_df %>%
  count(trt)
noncomp_trt <- noncomp_bytrt %>%
  pull(n) %>%
  set_names(pull(noncomp_bytrt, "trt"))

## Create final data frame with N, % of each noncompliance category
noncomp_npct <- noncompliance_df %>%
  dplyr::select(trt, one_of(noncomp_cats)) %>%
  group_by(trt) %>%
  summarise_all(sum_na) %>%
  ungroup() %>%
  gather(key = ntf_cat, value = cat_n, -trt) %>%
  spread(key = trt, value = cat_n) %>%
  bind_rows(noncomp_trt, .) %>%
  mutate(Overall = rowSums(.[, 1:(ncol(.) - 1)])) %>%
  ## Sort in order of overall total
  arrange(desc(Overall)) %>%
  ## Get percentages for each column in a hack-y sort of way; I really want
  ## modify2 to exist but it does not
  mutate(
    Haloperidol = ifelse(
      is.na(ntf_cat), as.character(Haloperidol),
      get_npct(num = Haloperidol, denom = pluck(noncomp_trt, "Haloperidol"))
    ),
    Ziprasidone =ifelse(
      is.na(ntf_cat), as.character(Ziprasidone),
      get_npct(num = Ziprasidone, denom = pluck(noncomp_trt, "Ziprasidone"))
    ),
    Placebo = ifelse(
      is.na(ntf_cat), as.character(Placebo),
      get_npct(num = Placebo, denom = pluck(noncomp_trt, "Placebo"))
    ),
    `Not randomized` = ifelse(
      is.na(ntf_cat), as.character(`Not randomized`),
      get_npct(
      num = `Not randomized`, denom = pluck(noncomp_trt, "Not randomized")
      )
    ),
    Overall = ifelse(
      is.na(ntf_cat), as.character(Overall),
      get_npct(num = Overall, denom = nrow(noncompliance_df))
    ),
    ntf_cat = case_when(
      is.na(ntf_cat) ~ "All noncompliance events",
      ntf_cat == "ntf_cat_other" ~ "Other category",
      ntf_cat == "ntf_cat_asmt" ~
        "Study assessment not completed, not documented",
      ntf_cat == "ntf_cat_titration" ~ "Study drug titration not as outlined",
      ntf_cat == "ntf_cat_specimen" ~
        "Blood specimens not collected as outlined",
      ntf_cat == "ntf_cat_incexc" ~ "Inclusion/exclusion criteria violation",
      ntf_cat == "ntf_cat_saeirb" ~ "SAE not reported appropriately to VCC",
      ntf_cat == "ntf_cat_saevcc" ~ "SAE not reported appropriately to IRB",
      TRUE ~ "[missing]"
    )
  ) %>%
  dplyr::select(
    ntf_cat, Placebo, Haloperidol, Ziprasidone, `Not randomized`, Overall
  )
Category of noncompliance Placebo Haloperidol Ziprasidone Not Randomized All Events
All noncompliance events 23 18 29 5 75
Other category 11 (48%) 7 (39%) 11 (38%) 5 (100%) 34 (45%)
Study assessment not completed, not documented 10 (43%) 7 (39%) 9 (31%) 0 (0%) 26 (35%)
Study drug titration not as outlined 2 (9%) 5 (28%) 10 (34%) 0 (0%) 17 (23%)
Blood specimens not collected as outlined 0 (0%) 1 (6%) 1 (3%) 0 (0%) 2 (3%)
Inclusion/exclusion criteria violation 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%)
SAE not reported appropriately to VCC 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%)
SAE not reported appropriately to IRB 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%)

For full transparency, we also include in the searchable table below details on each incidence of protocol noncompliance which increased patient risk. PHI in NTF explanations has been redacted.

Safety Outcomes and ABCDE Bundle Compliance

Our three primary safety outcomes are neuroleptic malignant syndrome (NMS); Torsades de pointes (Torsades); and extrapyramidal symptoms (EPS). Incidence of each was minimal and is detailed below.

We also collected data on daily performance of some elements of the ABCDEF Bundle; we describe compliance with these elements on a daily basis, both for all patient-days and for randomized patients during the intervention.

NMS

All suspected cases of NMS (i.e., patients in whom there was an initial suspicion of possible NMS) were rapidly reported to the DSMB for evaluation and the final determination of existence. No randomized patients ever experienced confirmed NMS during the study (during or outside the intervention phase).

Torsades de Pointes

During the intervention phase, 2 randomized patients experienced confirmed Torsades de pointes. Both instances were rapidly reported to the DSMB as “Torsades, clinical outcome”; descriptions of both events are included below, with potentially identifying details redacted. While both events were within the study drug period, neither patient was on study drug at the time of the event, and neither event was considered to be related to study drug.

Trt Study Phase Description
Haloperidol Study Drug Period

Fell at approximately xx/xx/xx, when standing up and resulted with facial trauma…. Patient was transferred to Neuro ICU at approximately xx/xx/xx for impending intubation. Intubated xx/xx/xx at xx/xx/xx for hypercarbic respiratory failure.

At xx/xx/xx the patient experienced a cardiac arrest with pulseless VTACH which also included Torsades de Pointes. ACLS was initiated with 1 round of CPR and no code drugs given and spontaneous return of sinus rhythm. Post event laboratory results indicated the patient was severely alkalemic and hypokalemic which “likely contributed to unstable tachyarrhythmia”
Haloperidol Study Drug Period Cardiac Arrest: Patient MOC-xx/xx/xx began to clinically decline in the evening of xx/xx/xx with respiratory distress and hypotension requiring the initiation of vasopressors and reintubation. After reintubation the patient was noticed to have lost pulses and ACLS was initatied, with an initial rhythm of PEA.There was a concern for torsades de pointes during ACLS. The patient persisted in PEA arrest and ACLS was stopped and patient declared dead at xx/xx/xx on xx/xx/xx.

EPS

To describe and determine the presence of extrapyramidal symptoms (EPS), we used a modified version of the Simpson-Angus Score which included elbow and wrist rigidity, glabellar tap, resting tremor, and salivation. Study drug was held if at least three out of these five symptoms had a score of 3 or higher on a given day; patients whose glabellar tap reflex could not be assessed were assigned a symptom score of 0. (Study drug was restarted if EPS resolved to a score of <3 on all categories.) Details for the 2 randomized patients who met this criteria at least once during the intervention period are shown below.

Trt Days met EPS criteria Overall EPS Score when Criteria Met Study drug held for EPS? Doses held for EPS
Ziprasidone 1 1.8 TRUE 1
Placebo 1 2.2 TRUE 4

ABCDE Compliance

We collected data on the following elements related to the ABCDEF Bundle, using the earlier definitions of “compliance” in place when study enrollment began. In order to be eligible for any of these on a given day, the patient had to have been in the ICU all 24 hours.

  • Awakening (SAT)
    • Eligible if: On invasive mechanical ventilation, and not off unit when staff attempted SAT
    • Compliant if: Received an SAT, or did not receive an SAT for a reason besides “other”
  • Breathing (SBT)
    • Eligible if: On invasive mechanical ventilation, and not off unit when staff attempted SBT
    • Compliant if: Received an SBT, or did not receive an SBT for a reason besides “other”
  • Coordination (Coordination of SAT and SBT)
    • Eligible if: On invasive MV and received both an SAT and SBT
    • Compliant if: Patient was off sedation when SBT was performed
  • Nonpharmacological interventions for delirium
    • Eligible if: Not comatose
    • Compliant if: Received >=1 nonpharmacological intervention (pain assessment/management, orientation, sensory, sleep)
  • Early mobility/exercise
    • Eligible if: Not off floor when staff attempted therapy
    • Compliant if: Was screened for safety, and either:
      • Failed safety screen for a recorded reason (MI, arrhythmia, FiO2, PEEP, or vasopressors)
      • Passed safety screen, but did not receive mobility due to sedatives/analgesics or refusal of patient, family, or clinical team
      • Received mobility
## -- One set of cols for all patient-days; one for all intervention days ------

## Wrapper function to combine results for intervention only, all patient-days
combine_abcde <- function(comp_fn){
  df_int <- do.call(comp_fn, list(daily_int_df %>% filter(intervention)))
  df_all <- do.call(comp_fn, list(daily_all_df))
  
  left_join(df_int, df_all, by = "Variable") %>%
    set_names(c("Variable", "Intervention Period", "All Patient-Days"))
}

## Awakening
get_comp_a <- function(df){
  days_elig <- sum_na(df$elig_a)
  days_comp <- sum_na(df$comp_a)
  days_sat <- sum_na(subset(df, comp_a)$sat_today)
  days_nosat <- sum_na(!subset(df, comp_a)$sat_today)
  days_sat_why <- map_int(
    names(df)[grepl("^sat\\_rsn\\_", names(df))],
    ~ sum_na(pluck(subset(df, comp_a), .))
  ) %>%
    set_names(
      gsub("^sat\\_rsn\\_", "", names(df)[grepl("^sat\\_rsn\\_", names(df))])
    )
  
  df_a <- tribble(
    ~ Variable,            ~ Days,                            ~ Denom,
    "Days Eligible",       days_elig,                         nrow(df),
    "Days Compliant",      days_comp,                         days_elig,
    "Had SAT",             days_sat,                          days_comp,
    "No SAT",              days_nosat,                        days_comp,
    "Seizures",            pluck(days_sat_why, "seizures"),   days_nosat,
    "Alcohol withdrawal",  pluck(days_sat_why, "alcohol"),    days_nosat,
    "Agitation",           pluck(days_sat_why, "agitation"),  days_nosat,
    "Paralytics",          pluck(days_sat_why, "paralytics"), days_nosat,
    "Myocardial ischemia", pluck(days_sat_why, "mi"),         days_nosat,
    "High ICP",            pluck(days_sat_why, "icp"),        days_nosat
  ) %>%
    mutate(
      Pct = get_npct(Days, Denom),
      sort_var = case_when(
        Variable == "Days Eligible" ~ 1,
        Variable == "Days Compliant" ~ 2,
        Variable == "Had SAT" ~ 3,
        Variable == "No SAT" ~ 4,
        TRUE ~ 5
      )
    ) %>%
    arrange(sort_var, desc(Days)) %>%
    dplyr::select(Variable, Pct)
  
  return(df_a)
}

## Breathing
get_comp_b <- function(df){
  days_elig <- sum_na(df$elig_b)
  days_comp <- sum_na(df$comp_b)
  days_sbt <- sum_na(subset(df, comp_b)$sbt_today)
  days_nosbt <- sum_na(!subset(df, comp_b)$sbt_today)
  days_sbt_why <- map_int(
    names(df)[grepl("^sbt\\_rsn\\_", names(df))],
    ~ sum_na(pluck(subset(df, comp_b), .))
  ) %>%
    set_names(
      gsub("^sbt\\_rsn\\_", "", names(df)[grepl("^sbt\\_rsn\\_", names(df))])
    )
  
  df_b <- tribble(
    ~ Variable,                    ~ Days,                           ~ Denom,
    "Days Eligible",               days_elig,                        nrow(df),
    "Days Compliant",              days_comp,                        days_elig,
    "Had SBT",                     days_sbt,                         days_comp,
    "No SBT",                      days_nosbt,                       days_comp,
    "Agitation",                   pluck(days_sbt_why, "agitation"), days_nosbt,
    "O2 sat <88%",                 pluck(days_sbt_why, "o2sat"),     days_nosbt,
    "FiO2 >50%",                   pluck(days_sbt_why, "fio2"),      days_nosbt,
    "PEEP >7.5cm H2O",             pluck(days_sbt_why, "peep"),      days_nosbt,
    "Myocardial ischemia",         pluck(days_sbt_why, "mi"),        days_nosbt,
    "Significant vasopressor use", pluck(days_sbt_why, "vasopressor"),        days_nosbt,
    "APRV/BiVent & P1 >24",        pluck(days_sbt_why, "aprv"),      days_nosbt
  ) %>%
    mutate(
      Pct = get_npct(Days, Denom),
      sort_var = case_when(
        Variable == "Days Eligible" ~ 1,
        Variable == "Days Compliant" ~ 2,
        Variable == "Had SBT" ~ 3,
        Variable == "No SBT" ~ 4,
        TRUE ~ 5
      )
    ) %>%
    arrange(sort_var, desc(Days)) %>%
    dplyr::select(Variable, Pct)
  
  return(df_b)
}

## Coordination
get_comp_c <- function(df){
  days_elig <- sum_na(df$elig_c)
  days_comp <- sum_na(df$comp_c)

  df_c <- tribble(
    ~ Variable,       ~ Days,    ~ Denom,
    "Days Eligible",  days_elig, nrow(df),
    "Days Compliant", days_comp, days_elig
  ) %>%
    mutate(
      Pct = get_npct(Days, Denom),
      sort_var = case_when(
        Variable == "Days Eligible" ~ 1,
        Variable == "Days Compliant" ~ 2,
        TRUE ~ 5
      )
    ) %>%
    arrange(sort_var, desc(Days)) %>%
    dplyr::select(Variable, Pct)
  
  return(df_c)
}

## Delirium
get_comp_d <- function(df){
  days_elig <- sum_na(df$elig_d)
  days_comp <- sum_na(df$comp_d)
  days_int_num <- map_int(
    1:4, ~ sum_na(subset(df, comp_d)$nonpharm_int == .)
  ) %>%
    set_names(1:4)
  days_int_each <- map_int(
    names(df)[grepl("^nonpharm\\_int\\_", names(df))],
    ~ sum_na(pluck(subset(df, comp_d), .))
  ) %>%
    set_names(
      gsub("^nonpharm\\_int\\_", "",
           names(df)[grepl("^nonpharm\\_int\\_", names(df))])
    )

  df_d <- tribble(
    ~ Variable,                   ~ Days,                          ~ Denom,
    "Days Eligible",              days_elig,                       nrow(df),
    "Days Compliant",             days_comp,                       days_elig,
    "One intervention",           pluck(days_int_num, "1"),        days_comp,
    "Two interventions",          pluck(days_int_num, "2"),        days_comp,
    "Three interventions",        pluck(days_int_num, "3"),        days_comp,
    "Four interventions",         pluck(days_int_num, "4"),        days_comp,
    "Pain assessment/management", pluck(days_int_each, "pain"),    days_comp,
    "Orientation",                pluck(days_int_each, "orient"),  days_comp,
    "Sensory",                    pluck(days_int_each, "sensory"), days_comp,
    "Sleep",                      pluck(days_int_each, "sleep"),   days_comp
  ) %>%
    mutate(
      Pct = get_npct(Days, Denom),
      sort_var = case_when(
        Variable == "Days Eligible" ~ 1,
        Variable == "Days Compliant" ~ 2,
        Variable == "One intervention" ~ 3,
        Variable == "Two interventions" ~ 4,
        Variable == "Three interventions" ~ 5,
        Variable == "Four interventions" ~ 6,
        TRUE ~ 7
      )
    ) %>%
    arrange(sort_var, desc(Days)) %>%
    dplyr::select(Variable, Pct)
  
  return(df_d)
}

## Delirium
get_comp_e <- function(df){
  days_elig <- sum_na(df$elig_e)
  days_comp <- sum_na(df$comp_e)
  days_mobility_each <- map_int(
    levels(df$mobility_highest),
    ~ sum_na(subset(df, comp_e)$mobility_highest == .)
  ) %>%
    set_names(gsub(" \\(.*$", "", levels(df$mobility_highest)))

  df_e <- tribble(
    ~ Variable,                   ~ Days,                            ~ Denom,
    "Days Eligible",              days_elig,                         nrow(df),
    "Days Compliant",             days_comp,                         days_elig,
    "L1 (Active ROM/sitting)", pluck(days_mobility_each, "Level 1"), days_comp,
    "L2 (Dangling)",           pluck(days_mobility_each, "Level 2"), days_comp,
    "L3 (Active transfers)",   pluck(days_mobility_each, "Level 3"), days_comp,
    "L4 (Marching/walking)",   pluck(days_mobility_each, "Level 4"), days_comp
  ) %>%
    mutate(
      Pct = get_npct(Days, Denom),
      sort_var = case_when(
        Variable == "Days Eligible" ~ 1,
        Variable == "Days Compliant" ~ 2,
        substr(Variable, 1, 2) == "L1" ~ 3,
        substr(Variable, 1, 2) == "L2" ~ 4,
        substr(Variable, 1, 2) == "L3" ~ 5,
        substr(Variable, 1, 2) == "L4" ~ 6,
        TRUE ~ 7
      )
    ) %>%
    arrange(sort_var, desc(Days)) %>%
    dplyr::select(Variable, Pct)
  
  return(df_e)
}

## Iterate over all elements to create final table
abcde_table <- map_df(
  list(get_comp_a, get_comp_b, get_comp_c, get_comp_d, get_comp_e),
  combine_abcde,
  .id = "element"
) %>%
  mutate(
    poptext = case_when(
      Variable == "Days Eligible" & element == "1" ~ "On invasive MV and on unit",
      Variable == "Days Compliant" & element == "1" ~
        "Received SAT, or no SAT for safety reason",
      Variable == "Days Eligible" & element == "2" ~ "On invasive MV and on unit",
      Variable == "Days Compliant" & element == "2" ~ "Received SBT, or no SBT for safety reason",
      Variable == "Days Eligible" & element == "3" ~ "On invasive MV, received SAT+SBT",
      Variable == "Days Compliant" & element == "3" ~ "Off sedation when SBT performed",
      Variable == "Days Eligible" & element == "4" ~ "Not comatose",
      Variable == "Days Compliant" & element == "4" ~ ">=1 nonpharmacological intervention",
      Variable == "Days Eligible" & element == "5" ~ "On unit",
      Variable == "Days Compliant" & element == "5" ~ "Screened and: failed screen; no mobility d/t meds or refusal; or received at least some mobility",
      Variable %in% c("No SAT", "No SBT") ~
        "For reason considered compliant, listed below",
      TRUE ~ ""
    ),
    poppos = "auto"
  )

abcde_table$Variable <- cell_spec(
  abcde_table$Variable,
  popover = spec_popover(
    content = abcde_table$poptext,
    title = NULL,
    position = abcde_table$poppos
  )
)

abcde_table %>%
  dplyr::select(2:4) %>%
  kable(
    escape = FALSE,
    format = "html",
    col.names = c("", "Intervention Period", "All Patient-Days"),
    align = c("l", "r", "r")
  ) %>%
  row_spec(c(1, 2, 11, 12, 22:25, 34, 35), bold = TRUE) %>%
  row_spec(c(5:10, 15:21), color = palette_colors[["lgray"]]) %>%
  group_rows("Awakening", 1, 10) %>%
  group_rows("Breathing", 11, 21) %>%
  group_rows("Coordination", 22, 23) %>%
  group_rows("Delirium", 24, 33) %>%
  group_rows("Early Mobility/Exercise", 34, 39) %>%
  mykablestyle()
Intervention Period All Patient-Days
Awakening
Days Eligible 2982 (38%) 4888 (52%)
Days Compliant 2791 (94%) 4494 (92%)
Had SAT 2310 (83%) 3695 (82%)
No SAT 481 (17%) 799 (18%)
Agitation 404 (84%) 605 (76%)
Paralytics 66 (14%) 148 (19%)
Alcohol withdrawal 28 (6%) 56 (7%)
Myocardial ischemia 5 (1%) 10 (1%)
Seizures 1 (0%) 6 (1%)
High ICP 0 (0%) 8 (1%)
Breathing
Days Eligible 2620 (33%) 4229 (45%)
Days Compliant 2473 (94%) 3939 (93%)
Had SBT 1724 (70%) 2669 (68%)
No SBT 749 (30%) 1270 (32%)
PEEP >7.5cm H2O 478 (64%) 803 (63%)
FiO2 >50% 306 (41%) 573 (45%)
Agitation 185 (25%) 259 (20%)
Significant vasopressor use 115 (15%) 192 (15%)
O2 sat <88% 35 (5%) 61 (5%)
APRV/BiVent & P1 >24 5 (1%) 14 (1%)
Myocardial ischemia 4 (1%) 10 (1%)
Coordination
Days Eligible 1557 (20%) 2435 (26%)
Days Compliant 1363 (88%) 2133 (88%)
Delirium
Days Eligible 3892 (49%) 6201 (66%)
Days Compliant 3846 (99%) 6123 (99%)
One intervention 291 (8%) 535 (9%)
Two interventions 1127 (29%) 1680 (27%)
Three interventions 1082 (28%) 1661 (27%)
Four interventions 1346 (35%) 2247 (37%)
Pain assessment/management 3786 (98%) 6030 (98%)
Orientation 3394 (88%) 5307 (87%)
Sleep 2103 (55%) 3413 (56%)
Sensory 1892 (49%) 3116 (51%)
Early Mobility/Exercise
Days Eligible 4154 (52%) 6940 (74%)
Days Compliant 3626 (87%) 6204 (89%)
L1 (Active ROM/sitting) 1645 (45%) 2584 (42%)
L2 (Dangling) 222 (6%) 372 (6%)
L3 (Active transfers) 411 (11%) 719 (12%)
L4 (Marching/walking) 136 (4%) 326 (5%)

ABCDE Compliance by Treatment Group

The following describes ABCDE Bundle element compliance by treatment group during the 14-day intervention period only.

Placebo Haloperidol Ziprasidone
Awakening
Days Eligible 968 (38%) 979 (36%) 1035 (39%)
Days Compliant 917 (95%) 895 (91%) 979 (95%)
Had SAT 739 (81%) 759 (85%) 812 (83%)
No SAT 178 (19%) 136 (15%) 167 (17%)
Agitation 134 (75%) 127 (93%) 143 (86%)
Paralytics 40 (22%) 6 (4%) 20 (12%)
Alcohol withdrawal 15 (8%) 5 (4%) 8 (5%)
Myocardial ischemia 2 (1%) 2 (1%) 1 (1%)
Seizures 1 (1%) 0 (0%) 0 (0%)
High ICP 0 (0%) 0 (0%) 0 (0%)
Breathing
Days Eligible 838 (33%) 886 (33%) 896 (34%)
Days Compliant 793 (95%) 831 (94%) 849 (95%)
Had SBT 527 (66%) 571 (69%) 626 (74%)
No SBT 266 (34%) 260 (31%) 223 (26%)
PEEP >7.5cm H2O 180 (68%) 175 (67%) 123 (55%)
FiO2 >50% 102 (38%) 116 (45%) 88 (39%)
Agitation 59 (22%) 68 (26%) 58 (26%)
Significant vasopressor use 47 (18%) 33 (13%) 35 (16%)
O2 sat <88% 17 (6%) 13 (5%) 5 (2%)
Myocardial ischemia 3 (1%) 1 (0%) 0 (0%)
APRV/BiVent & P1 >24 0 (0%) 2 (1%) 3 (1%)
Coordination
Days Eligible 479 (19%) 525 (20%) 553 (21%)
Days Compliant 407 (85%) 473 (90%) 483 (87%)
Delirium
Days Eligible 1268 (49%) 1327 (49%) 1297 (49%)
Days Compliant 1247 (98%) 1317 (99%) 1282 (99%)
One intervention 90 (7%) 94 (7%) 107 (8%)
Two interventions 393 (32%) 352 (27%) 382 (30%)
Three interventions 371 (30%) 380 (29%) 331 (26%)
Four interventions 393 (32%) 491 (37%) 462 (36%)
Pain assessment/management 1224 (98%) 1305 (99%) 1257 (98%)
Orientation 1118 (90%) 1139 (86%) 1137 (89%)
Sleep 645 (52%) 795 (60%) 663 (52%)
Sensory 574 (46%) 663 (50%) 655 (51%)
Early Mobility/Exercise
Days Eligible 1374 (53%) 1388 (52%) 1392 (52%)
Days Compliant 1229 (89%) 1168 (84%) 1229 (88%)
L1 (Active ROM/sitting) 538 (44%) 524 (45%) 583 (47%)
L2 (Dangling) 83 (7%) 68 (6%) 71 (6%)
L3 (Active transfers) 121 (10%) 142 (12%) 148 (12%)
L4 (Marching/walking) 41 (3%) 63 (5%) 32 (3%)

Exploration of Missing Data & Potential Redundancy

We examine all outcomes and covariates to determine how much missing data is present. In short, we have no missingness for our outcomes and very little for our covariates; therefore, we will perform complete case analysis only. Expand below for further information.

## -- Create dataset with only outcomes, covariates ----------------------------
outcome_vars <- c(
  "dcfd_int", "del_int_all", "hyperdel_int_all", "hypodel_int_all",
  "coma_int_all",
  "tte_death_30", "event_death_30",     ## Time to death within 30 days
  "tte_death_90", "event_death_90",     ## Time to death within 90 days
  "tte_icudis_90", "ftype_icudis_90",   ## Time to final, succ. ICU discharge
  "tte_hospdis_90", "ftype_hospdis_90", ## Time to hospital discharge
  "tte_mvlib_30", "ftype_mvlib_30",     ## Time to liberation from MV
  "tte_readm_90", "ftype_readm_90"      ## Time to ICU readmission
)

covariate_vars <- c(
  "age_consent", "charlson_total", "iqcode_total_ph", "frailty",
  "sofa_mod_imp_rand", "trt"
)

em_vars <- c("med_surg", "sepsis_adm")

model_df <- ptsummary_df %>%
  dplyr::select(
    id, study_site, on_mv_rand24, rass_rand, elig_readm,
    one_of(outcome_vars), one_of(covariate_vars), one_of(em_vars)
  ) %>%
  ## Create category for level of arousal at randomization,
  ##   using RASS closest to time of randomization within 5 hours
  mutate(
    arousal_rand = factor(
      case_when(
        is.na(rass_rand) ~ as.numeric(NA),
        rass_rand %in% c(-3) ~ 1,
        rass_rand %in% c(-2, -1) ~ 2,
        rass_rand %in% c(0) ~ 3,
        TRUE ~ 4
      ),
      levels = 1:4,
      labels = c("Deeply sedated", "Lightly sedated", "Normal", "Agitated")
    )
  )

## Add newly created arousal_rand to covariate_vars
covariate_vars <- c(covariate_vars, "arousal_rand")

## Add indicator for complete covariate data
model_df$comp_covars <- rowSums(is.na(model_df[, covariate_vars])) == 0
## How many randomized patients have complete covariate data?
n_rand_comp <- sum_na(model_df$comp_covars)

## What % of patients are missing at least one covariate/outcome?
## (This does *not* include variables related to liberation from MV or ICU
## readmission, as that would introduce artificial missingness)
pts_missany <- model_df %>%
  dplyr::select(
    covariate_vars, outcome_vars[!grepl("^tte|ftype|event", outcome_vars)]
  ) %>%
  miss_case_table() %>%
  filter(n_miss_in_case > 0) %>%
  summarise(
    nmiss = sum_na(n_cases),
    pctmiss = sum_na(pct_miss)
  )

pts_missany_trt <- model_df %>%
  dplyr::select(
    covariate_vars, outcome_vars[!grepl("^tte|ftype|event", outcome_vars)]
  ) %>%
  group_by(trt) %>%
  miss_case_table() %>%
  ungroup() %>%
  filter(n_miss_in_case > 0) %>%
  group_by(trt) %>%
  summarise(
    nmiss = sum_na(n_cases),
    pctmiss = sum_na(pct_miss)
  )

## Set datadist to this data.frame
dd <- datadist(model_df, adjto.cat = "first")
options(datadist = "dd")

## -- Create sparklines to show distributions ----------------------------------
create_spark <- function(
  vname,                                 ## variable name; must be in df
  vbreaks = NULL,                        ## breaks to bin data, if desired
  spark_id = sprintf("spark-%s", vname), ## name of sparkline element
  spark_width = 50,                      ## sparkline width
  df = model_df                          ## data.frame to use
){
  if(is.null(vbreaks)){
    df$vcuts <- df[, vname]
  } else{
    df$vcuts <- cut(df[, vname], breaks = vbreaks)
  }
  
  barhts <- df %>%
    group_by(vcuts) %>%
    summarise(count = n())
  
  sparkline(
    barhts$count,
    type = "bar",
    barColor = as.character(palette_colors["dred"]),
    elementId = spark_id,
    width = spark_width
  )
}

spark_iqcode <- create_spark(
  "iqcode_total_ph",
  vbreaks = seq(0, 5, 0.25),
  spark_id = "spark-iqcode"
)

spark_dcfd <- create_spark(
  "dcfd_int",
  # vbreaks = seq(-1, 14, 1),
  spark_id = "spark-dcfd",
  spark_width = 50
)

spark_del <- create_spark(
  "del_int_all",
  # vbreaks = seq(-1, 14, 1),
  spark_id = "spark-del",
  spark_width = 50
)

spark_hyperdel <- create_spark(
  "hyperdel_int_all",
  # vbreaks = seq(-1, 14, 1),
  spark_id = "spark-hyperdel",
  spark_width = 50
)

spark_hypodel <- create_spark(
  "hypodel_int_all",
  # vbreaks = seq(-1, 14, 1),
  spark_id = "spark-hypodel",
  spark_width = 50
)

spark_coma <- create_spark(
  "coma_int_all",
  # vbreaks = seq(-1, 14, 1),
  spark_id = "spark-coma",
  spark_width = 50
)

## -- Create model RHS for multiple uses ---------------------------------------
## How many knots for continuous covariates? Which ones are continuous?
rcsknots <- 3
cont_covars <- c(
  "age_consent", "charlson_total", "frailty", "sofa_mod_imp_rand"
)
notcont_covars <- c(setdiff(covariate_vars, c(cont_covars, "trt")), "trt")
 ## always put trt at the end - helpful for working with model.matrix()

mod_rhs <- map_chr(cont_covars, ~ sprintf("rcs(%s, %s)", ., rcsknots)) %>%
  c(., notcont_covars) %>%
  paste(collapse = " + ")

## For testing purposes: RHS, no splines
mod_rhs_lin <- paste(c(covariate_vars, em_vars, "study_site"), collapse = " + ")

Summary of Covariate & Outcome Missingness

IQCODE (9 patients) and level of arousal at randomization (4 patients) are the only covariates with missing data; the amount is still quite minimal (<2% for each), and these variables are not missing in ways that appear to be related. In the plot below, red indicates missingness and blue indicates a present value. Cases which have both variables missing would be in red in the lower lefthand corner.

(Level of arousal at randomization is more specifically defined as the recorded RASS that is not comatose [ie, > -3] and closest to the time of randomization, as long as it is within 5 hours before or after randomization.)

This is based on the RASS closest to randomization (before or after the time noted), assuming it was 1) not comatose (>-3) and 2) within 5 hours of randomization. There were 4 patients with no recorded non-comatose RASS within those 5 hours.

To make sure none of our covariates completely explain any of the others (resulting in collinearity), we perform a redundancy analysis, detailed below. No covariates suggest evidence of too-high collinearity.

## 
## Redundancy Analysis
## 
## Hmisc::redun(formula = ~age_consent + charlson_total + frailty + 
##     sofa_mod_imp_rand + I(iqcode_total_ph) + arousal_rand + trt, 
##     data = model_df, nk = rcsknots)
## 
## n: 553   p: 7    nk: 3 
## 
## Number of NAs:    13 
## Frequencies of Missing Values Due to Each Variable
##        age_consent     charlson_total            frailty 
##                  0                  0                  0 
##  sofa_mod_imp_rand I(iqcode_total_ph)       arousal_rand 
##                  0                  9                  4 
##                trt 
##                  0 
## 
## 
## Transformation of target variables forced to be linear
## 
## R-squared cutoff: 0.9    Type: ordinary 
## 
## R^2 with which each variable can be predicted from all other variables:
## 
##        age_consent     charlson_total            frailty 
##              0.191              0.186              0.245 
##  sofa_mod_imp_rand I(iqcode_total_ph)       arousal_rand 
##              0.094              0.160              0.037 
##                trt 
##              0.021 
## 
## No redundant variables

Statistical Methods


Our full, prespecified Statistical Analysis Plan includes more detailed information on database management, data cleaning, study methods, and guiding statistical principles. The version in place prior to breaking the treatment blind is registered on the Open Science Framework. Any further updates to the SAP, in addition to other study documents and R code for analysis, will be available via the project’s primary OSF project page.

Unadjusted Analysis

In-Hospital Continuous Outcomes

We analyze continuous outcomes (delirium/coma-free days, delirium duration, and coma duration) using the Kruskal-Wallis test. These outcomes are not normally distributed (see each section for further details); therefore, the assumptions for a parametric ANOVA would be violated, and results would be unreliable. The nonparametric Kruskal-Wallis test does not assume that the outcome has a specific distribution, and thus provides more power and reliability in the case of a non-normal distribution.

Time to Event Outcomes

We describe and test for differences in time to death using Kaplan-Meier curves and the log-rank test, respectively.

Our other time-to-event outcomes (ICU and hospital discharge, liberation from mechanical ventilation, and ICU readmission), have a competing risk of death, with an additional competing risk of hospital discharge for the latter two. This means that patients who experience death (or discharge) do not have the opportunity to experience the outcome of interest. Traditional survival analysis assumes that that the reason for censoring is independent of the outcome; here, that is not the case. Kaplan-Meier curves would be misleading in these scenarios, because they do not take these “competing risks” into account. Therefore, we describe together the cumulative incidences of both the outcome of interest and death (and discharge, if applicable), along with score tests for the difference between groups in the subdistribution of interest.

Generally, the 3 patients who withdrew in the hospital with no discharge or death information available are censored at the time of withdrawal; we censor at x.01 days anyone who has experienced neither outcome of interest nor the competing risks by x days, where x is the time frame for the specified outcome. More details on censoring are provided with each analysis.

Adjusted Analysis

Multivariable Modeling

We perform multivariable regression analyses to explore the association between treatment group and our outcome variables while adjusting for potential baseline confounders. Though these covariates should be balanced between treatment groups thanks to randomization, adjustment increases our power and precision. We performed a redundancy analysis1 to ensure that no covariates completely explain any of the others (resulting in collinearity); see above. No covariates suggest evidence of too-high collinearity.

In addition, we adjust all coefficient variances using Huber-White sandwich estimation, clustered by study site. This will help account for unmeasured variability and correlation among patients within a given site.

In-Hospital Continuous Outcomes

We use proportional odds logistic regression for continuous outcomes (delirium/coma-free days, delirium duration, and coma duration); this method assumes an ordinal outcome but does not assume that it follows a specific statistical distribution.

Time to Event Outcomes

We use Cox proportional hazards regression for mortality. For all other time to event outcomes (ICU and hospital discharge and liberation from mechanical ventilation), we use competing risks regression2, treating death as our competing risk. Generally, the 3 patients who withdrew in the hospital with no discharge or death information available are censored at the time of withdrawal; we censor at x.01 days anyone who has experienced neither death nor the outcome of interest by x days, where x is the time frame in question (30 days for liberation from mechanical ventilation; 90 days for ICU and hospital discharge and ICU readmission; both time points for mortality). More details on censoring are provided with each analysis.

Model Assumptions

We check proportional odds and proportional hazards assumptions graphically for each model. When checking the proportional odds assumption, something may be amiss if Y axis values (estimated coefficient at various cutoffs of our outcome) change substantially across the X axis, particularly if the effect changes direction (noted by the dotted line at 0). For further discussion, please see Harrell’s Regression Modeling Strategies, section 13.3.3

For the proportional hazard assumption, we are looking for fairly flat associations between beta coefficients (Y axis) and time (X axis), which would indicate that the hazard remains constant over time.

Covariates

All multivariable models are adjusted for the following baseline covariates, in addition to treatment group:

  • Age at study consent
  • Preexisting CI, via the IQCODE (performed via patient or surrogate questionnaire)
  • Preexisting frailty, via the CSHA Clinical Frailty Score
  • Preexisting comorbidities, via the Charlson Comorbidities Index
  • SOFA on the day of randomization, excluding the CNS component
  • Level of arousal at randomization, via the RASS closest to the time of randomization. Categorized as:
    • Deeply sedated (RASS -3)
    • Lightly sedated (RASS -2 or -1)
    • Normal (RASS 0)
    • Agitated (RASS > 0)

Age, CFS, Charlson, and modified SOFA at randomization are all allowed to have a nonlinear relationship with our outcome, using restricted cubic splines with 3 knots. The distribution of IQCODE (42% of patients had a score of exactly 3) has too little variability to allow this flexibility. (Level of arousal and treatment are both categorical covariates, and thus nonlinearity does not apply.)

Heterogeneity of Treatment Effect

We are interested in whether any association between treatment group and our main outcomes is modified by several factors. In secondary analyses, we will include interaction (or cross-product) terms in our multivariable models between treatment and the following variables:

  • Age at consent
  • Severity of illness, measured by modified SOFA on the day of randomization
  • Pre-existing cognitive impairment, measured by IQCODE at consent
  • Severe sepsis, as defined by primary reason for ICU admission
  • Medical vs surgical patient, as defined by meeting at least one of the following criteria:
    • Recorded primary ICU admission reason involving “surgery”
    • Emergency or elective surgery between hospital admission and ICU admission
    • Went to the OR between ICU admission and study enrollment

Missing Data

We have very little missing covariate or outcome data (see above for further details); therefore, we use complete case analysis for all in-hospital outcomes. From models which would include all 566 randomized patients (all except liberation from mechanical ventilation and ICU readmission), complete case analysis excludes 13 (2%; Placebo, 4; Haloperidol, 4; Ziprasidone, 5).

We do use single imputation for missing mental status on a daily basis, to reduce potential bias from the 4% of patient-days during the intervention period without sufficient RASS and/or CAM information to determine mental status. Please see Notes on Variable Calculation for further rationale and details.

Software Summary

We used R version 3.4.4 (2018-03-15) for all analyses and data management. Full package details can be found below; specific packages used for major components include:

Package Version Updated Source Used for
cmprsk 2.2-7 2014-06-17 CRAN (R 3.4.4) Competing risks survival analysis
rms 5.1-2 2018-01-07 CRAN (R 3.4.4) Multivariable regression
survival 2.42-6 2018-07-13 CRAN (R 3.4.4) General survival analysis
survminer 0.4.2 2018-01-31 CRAN (R 3.4.4) Presentation of survival data

We also used R for all data management. Links to all R code for both data management and this analysis can be found on the Open Science Framework.

In addition, we use the checkpoint package for reproducibility. This package downloaded R package versions on CRAN as of May 14, 2018, and will use these versions going forward, regardless of future software updates. (The ggthemr and JTHelpers packages, solely housed on Github, were also installed in this directory on the same date.)

Primary Analysis

This section includes analyses for the entire randomized cohort, with no potential effect modification (no interaction terms).


## -- Setup for Liu & Shepherd's functions to calculate conditional median, ----
## -- CI for POLR models (see chunk orm_functions) -----------------------------

## First step: create newdata with median, mode values
## We can use datadist() to our advantage here. In the $limits element, the
##  second value for each variable is `Adjust to` and is by default the median
##  or mode. We'll also need to manually include the values for any associated
##  spline terms.

## First: Get locations of knots for all continuous covariates
knot_locations <- set_names(
  map(
    cont_covars,
    ~ rcspline.eval(model_df[, .], nk = rcsknots, knots.only = TRUE)
  ),
  cont_covars
)

## Function to get value(s) of each covariate to adjust predicted values to
##   (median/mode, plus any spline terms)
get_adjvals <- function(
  vname,                      ## string; variable name (must be in dd)
  ddist,                      ## datadist() object
  use_rcs = TRUE,             ## whether to include spline terms
  knot_locs = knot_locations  ## locations of knots for variable vname
){
  ## We'll return every result as a data.frame with reasonable names,
  ##  so it can be easily cbinded later
  
  ## base_value = "Adjust to" value for vname
  base_value <- ddist$limits[2, vname]
  
  ## If we're using splines in this model, and variable is in our list of
  ## variables we use with splines (that's in the global env SORRY), use
  ## rcspline.eval() to extract both original and spline term values
  if(use_rcs && vname %in% cont_covars){
    df <- rcspline.eval(
      base_value, knots = pluck(knot_locs, vname), inclx = TRUE
    ) %>%
      as.data.frame()
    
    ## Set reasonable column names: eg, "age", "age_2"
    mynames <- names(df)
    mynames <- map_chr(1:ncol(df), ~ paste(vname, ., sep = "_"))
    mynames <- gsub("\\_1", "", mynames)
    names(df) <- mynames
  } else{
    ## If variable doesn't use splines, return base_value as a data.frame
    df <- set_names(as.data.frame(base_value), vname)
  }
  
  return(df)
}

Delirium/Coma-Free Days

Unadjusted Analysis

Due to the non-normal distribution of DCFDs , our primary unadjusted analysis uses a Kruskal-Wallis test to look for any differences in distribution of this outcome between the three treatment groups. Please see the Methods section for more details. All 566 randomized patients are included.

We see no association between treatment group and DCFDs.

DCFDs.
Placebo
N=184
Haloperidol
N=192
Ziprasidone
N=190
Test Statistic
Days alive, free of delirium & coma 0.0 7.0 11.2
6.3 ±  5.1
0.0 8.0 11.0
6.6 ±  4.9
2.0 8.0 11.0
6.8 ±  4.8
F2 563=0.38, P=0.69
a b c represent the lower quartile a, the median b, and the upper quartile c for continuous variables. x ± s represents X ± 1 SD.
Test used: Kruskal-Wallis test .

Adjusted Analysis

After adjusting for all baseline covariates, we again see no significant association between treatment and days alive and free of delirium and coma during the intervention period.

Model Results

We show the odds ratios (using placebo as reference) and adjusted medians for DCFDs by treatment group.

Adjusted Odds Ratios

Odds ratios higher than 1 are favorable, indicating higher odds of more “good” days alive and free of brain dysfunction.

## -- Create dataset of values to use when calculating conditional medians -----
## Since we use the same covariates for all three models, can use this dataset
## 1. Create data frame with a single row, excluding treatment values
##  (we'll add those later)
pred_df_org <- map_dfc(
  setdiff(c(cont_covars, notcont_covars), "trt"),
  get_adjvals,
  ddist = dd
)

## 2. Repeat those values by row; # rows = # different treatments
pred_df <- rep(list(pred_df_org), length(levels(model_df$trt))) %>%
  bind_rows() %>%
  ## Add treatment levels
  bind_cols(trt = levels(model_df$trt)) %>%
  ## Create a model.matrix object, then leave out the intercept
  ##   model.matrix() handles dummy variables for categoricals nicely
  model.matrix(
    as.formula(sprintf("~ %s", paste(names(.), collapse = " + "))),
    .
  ) %>%
  ## Could not get the contrasts argument to give me placebo as reference.
  ## Wrangle this thing by hand.
  as.data.frame() %>%
  dplyr::select(-1, -starts_with("trt")) %>%
  bind_cols(as.data.frame(contr.treatment(levels(model_df$trt), base = 1)))

## colnames must be the same as names(coef(model))
## We're using the same covariates for all models, so we can just use one
pred_df_names <- names(coef(dcfd_mod))
pred_df_names <- pred_df_names[grepl("^[^y>=]", pred_df_names)]
pred_df_names <- pred_df_names[grepl("^[^trt=]", pred_df_names)]
pred_df_names <-
  c(pred_df_names, paste0("trt=", c("Haloperidol", "Ziprasidone")))
names(pred_df) <- pred_df_names

## -- Calculate, plot odds ratios for both treatments vs placebo ---------------
dcfd_ors <- trt_ratios(mod = dcfd_mod)

dcfd_ors_plot <- plot_trt_ratios(
  ratio_df = dcfd_ors,
  "Delirium/Coma-Free Days",
  mod = dcfd_mod
)

dcfd_ors_plot

Adjusted Medians

Medians are adjusted to the median/mode values of all covariates, so that each represents the expected median number of DCFDs for a patient in each treatment group who is otherwise part of a “typical” (many air quotes) population.

Results for All Covariates

Since most of the continuous covariates are modeled using restricted cubic splines (see the Methods section for more details), a single odds ratio/CI is insufficient to describe the entire relationship between each of these covariates and DCFDs. Rather, each odds ratio reflects a comparison between two specific values of the covariate, as noted in the table.

Variable Reference Comparison Odds Ratio (95% CI) X2 df P
age_consent 51.36 68.68 0.65 (0.53, 0.80) 23.2 2 <0.001
arousal_rand Deeply sedated Lightly sedated 1.84 (1.45, 2.34) 69.4 3 <0.001
Deeply sedated Normal 3.33 (1.81, 6.11)
Deeply sedated Agitated 1.24 (0.93, 1.66)
charlson_total 1.00 4.00 1.17 (1.01, 1.35) 4.3 2 0.119
frailty 3.00 5.00 0.80 (0.67, 0.94) 7.6 2 0.023
iqcode_total_ph 3.00 3.25 0.94 (0.85, 1.03) 1.6 1 0.203
sofa_mod_imp_rand 4.00 9.00 0.54 (0.38, 0.75) 54.0 2 <0.001
trt Placebo Haloperidol 0.88 (0.64, 1.21) 2.7 2 0.262
Placebo Ziprasidone 1.04 (0.73, 1.48)
All Nonlinear Terms 10.0 4 0.040
Overall Model 464.1 14 <0.001
Model L.R. 78.06
C 0.63
Dxy 0.27
R2 0.13
Observations 553

Delirium Duration

Delirium duration is an imperfect measure, since patients who die quickly can have a short duration and appear to have better outcomes than they actually do. It is included as a way to help elucidate any association between treatment and our blunt primary outcome of DCFDs, which incorporates delirium and coma durations as well as death.

Unadjusted Analysis

Due to the non-normal distribution of delirium duration , our primary unadjusted analysis uses a Kruskal-Wallis test to look for any differences in distribution of this outcome between the three treatment groups. Please see the Methods section for more details. All 566 randomized patients are included.

We see no association between treatment and days of delirium during the intervention period.

Days of Delirium.
Placebo
N=184
Haloperidol
N=192
Ziprasidone
N=190
Test Statistic
Days of delirium 2.0 4.0 8.0
5.3 ± 4.1
2.0 4.0 7.0
5.2 ± 3.8
2.0 4.0 6.0
4.8 ± 3.3
F2 563=0.17, P=0.84
a b c represent the lower quartile a, the median b, and the upper quartile c for continuous variables. x ± s represents X ± 1 SD.
Test used: Kruskal-Wallis test .

Adjusted Analysis

After adjusting for all baseline covariates, we again see no significant association between treatment and days of delirium during the intervention period.

Model Results

We show the odds ratios (using placebo as reference) and adjusted medians for delirium duration by treatment group.

Adjusted Medians

Medians are adjusted to the median/mode values of all covariates, so that each represents the expected median number of days with delirium for a patient in each treatment group who is otherwise part of a “typical” (many air quotes) population.

Results for All Covariates

Since most of the continuous covariates are modeled using restricted cubic splines (see the Methods section for more details), a single odds ratio/CI is insufficient to describe the entire relationship between each of these covariates and delirium duration. Rather, each odds ratio reflects a comparison between two specific values of the covariate, as noted in the table.

Variable Reference Comparison Odds Ratio (95% CI) X2 df P
age_consent 51.36 68.68 1.49 (1.27, 1.74) 24.6 2 <0.001
arousal_rand Deeply sedated Lightly sedated 0.63 (0.50, 0.80) 19.4 3 <0.001
Deeply sedated Normal 0.41 (0.20, 0.82)
Deeply sedated Agitated 0.91 (0.65, 1.28)
charlson_total 1.00 4.00 0.78 (0.60, 1.03) 3.2 2 0.204
frailty 3.00 5.00 0.98 (0.83, 1.17) 0.0 2 0.979
iqcode_total_ph 3.00 3.25 1.02 (0.93, 1.12) 0.2 1 0.667
sofa_mod_imp_rand 4.00 9.00 1.12 (0.79, 1.58) 5.2 2 0.076
trt Placebo Haloperidol 1.12 (0.86, 1.46) 1.6 2 0.459
Placebo Ziprasidone 1.02 (0.69, 1.51)
All Nonlinear Terms 1.3 4 0.869
Overall Model 403.0 14 <0.001
Model L.R. 29.34
C 0.59
Dxy 0.17
R2 0.05
Observations 553

Duration of Hyperactive Delirium

In addition to any delirium, we are interested in any differential association between treatment and either hypoactive or hyperactive delirium. Here, we look at treatment vs hyperactive delirium, defined as delirium with a RASS > 0.

Unadjusted Analysis

Due to the non-normal distribution of hyperactive delirium duration , our primary unadjusted analysis uses a Kruskal-Wallis test to look for any differences in distribution of this outcome between the three treatment groups. Please see the Methods section for more details. All 566 randomized patients are included.

We see no association between treatment and days of hyperactive delirium during the intervention period.

Days of Hyperactive Delirium.
Placebo
N=184
Haloperidol
N=192
Ziprasidone
N=190
Test Statistic
Days of hyperactive delirium 0.00 0.00 1.00
0.72 ± 1.21
0.00 0.00 1.00
0.79 ± 1.29
0.00 0.00 1.00
0.69 ± 1.33
F2 563=0.44, P=0.64
a b c represent the lower quartile a, the median b, and the upper quartile c for continuous variables. x ± s represents X ± 1 SD.
Test used: Kruskal-Wallis test .

Adjusted Analysis

After adjusting for all baseline covariates, we again see no significant association between treatment and days of hyperactive delirium during the intervention period.

Model Fitting and Assumptions

Model Fitting

We use proportional odds logistic regression to look at the association between treatment and duration of hyperactive delirium during the intervention period, adjusting for baseline patient characteristics. Please see the Methods section for more details. All 553 randomized patients with complete covariate data are included.

Model Results

We show the odds ratios (using placebo as reference) and adjusted medians for delirium duration by treatment group.

Adjusted Medians

Medians are adjusted to the median/mode values of all covariates, so that each represents the expected median number of days with hyperactive delirium for a patient in each treatment group who is otherwise part of a “typical” (many air quotes) population.

Results for All Covariates

Since most of the continuous covariates are modeled using restricted cubic splines (see the Methods section for more details), a single odds ratio/CI is insufficient to describe the entire relationship between each of these covariates and delirium duration. Rather, each odds ratio reflects a comparison between two specific values of the covariate, as noted in the table.

Variable Reference Comparison Odds Ratio (95% CI) X2 df P
age_consent 51.36 68.68 1.10 (0.80, 1.50) 0.6 2 0.749
arousal_rand Deeply sedated Lightly sedated 0.94 (0.70, 1.26) 251.0 3 <0.001
Deeply sedated Normal 0.47 (0.32, 0.67)
Deeply sedated Agitated 13.25 (8.20, 21.39)
charlson_total 1.00 4.00 0.69 (0.47, 1.02) 3.6 2 0.163
frailty 3.00 5.00 0.90 (0.68, 1.18) 1.8 2 0.415
iqcode_total_ph 3.00 3.25 0.92 (0.84, 1.01) 3.2 1 0.076
sofa_mod_imp_rand 4.00 9.00 1.07 (0.78, 1.48) 1.6 2 0.454
trt Placebo Haloperidol 1.18 (0.86, 1.61) 1.1 2 0.581
Placebo Ziprasidone 1.09 (0.70, 1.70)
All Nonlinear Terms 7.4 4 0.118
Overall Model 1123.1 14 <0.001
Model L.R. 118.01
C 0.69
Dxy 0.38
R2 0.21
Observations 553

Duration of Hypoactive Delirium

In addition to any delirium, we are interested in any differential association between treatment and either hypoactive or hypoactive delirium. Here, we look at treatment vs hypoactive delirium, defined as delirium with a RASS <= 0.

Unadjusted Analysis

Due to the non-normal distribution of hypoactive delirium duration , our primary unadjusted analysis uses a Kruskal-Wallis test to look for any differences in distribution of this outcome between the three treatment groups. Please see the Methods section for more details. All 566 randomized patients are included.

We see no association between treatment group and days of hypoactive delirium during the intervention period.

Days of Hypoactive Delirium.
Placebo
N=184
Haloperidol
N=192
Ziprasidone
N=190
Test Statistic
Days of hypoactive delirium 2.0 3.0 8.0
4.9 ± 3.9
2.0 4.0 6.0
4.7 ± 3.7
2.0 3.0 6.0
4.4 ± 3.1
F2 563=0.08, P=0.92
a b c represent the lower quartile a, the median b, and the upper quartile c for continuous variables. x ± s represents X ± 1 SD.
Test used: Kruskal-Wallis test .

Adjusted Analysis

After adjusting for all baseline covariates, we again see no significant association between treatment and days of hypoactive delirium during the intervention period.

Model Fitting and Assumptions

Model Fitting

We use proportional odds logistic regression to look at the association between treatment and duration of hypoactive delirium during the intervention period, adjusting for baseline patient characteristics. Please see the Methods section for more details. All 553 randomized patients with complete covariate data are included.

Assumptions

We are looking for fairly flat lines, paying particular attention to panels representing treatment groups. Please see the Methods section for further details.

Model Results

We show the odds ratios (using placebo as reference) and adjusted medians for duration of hypoactive delirium by treatment group.

Adjusted Medians

Medians are adjusted to the median/mode values of all covariates, so that each represents the expected median number of days with hypoactive delirium for a patient in each treatment group who is otherwise part of a “typical” (many air quotes) population.

Results for All Covariates

Since most of the continuous covariates are modeled using restricted cubic splines (see the Methods section for more details), a single odds ratio/CI is insufficient to describe the entire relationship between each of these covariates and delirium duration. Rather, each odds ratio reflects a comparison between two specific values of the covariate, as noted in the table.

Variable Reference Comparison Odds Ratio (95% CI) X2 df P
age_consent 51.36 68.68 1.51 (1.29, 1.76) 28.4 2 <0.001
arousal_rand Deeply sedated Lightly sedated 0.64 (0.51, 0.79) 25.6 3 <0.001
Deeply sedated Normal 0.44 (0.22, 0.89)
Deeply sedated Agitated 0.38 (0.22, 0.67)
charlson_total 1.00 4.00 0.80 (0.61, 1.05) 2.8 2 0.253
frailty 3.00 5.00 1.00 (0.85, 1.18) 0.4 2 0.825
iqcode_total_ph 3.00 3.25 1.02 (0.92, 1.13) 0.2 1 0.680
sofa_mod_imp_rand 4.00 9.00 1.17 (0.83, 1.66) 7.6 2 0.022
trt Placebo Haloperidol 1.10 (0.81, 1.48) 1.0 2 0.620
Placebo Ziprasidone 1.00 (0.68, 1.47)
All Nonlinear Terms 2.8 4 0.591
Overall Model 73.5 14 <0.001
Model L.R. 34.15
C 0.59
Dxy 0.18
R2 0.06
Observations 553

Coma Duration

Coma duration is an imperfect measure, since patients who die quickly can have a short duration and appear to have better outcomes than they actually do. It is included as a way to help elucidate any association between treatment and our blunt primary outcome of DCFDs, which incorporates delirium and coma durations as well as death.

Unadjusted Analysis

Due to the non-normal distribution of coma duration , our primary unadjusted analysis uses a Kruskal-Wallis test to look for any differences in distribution of this outcome between the three treatment groups. Please see the Methods section for more details. All 566 randomized patients are included.

We see no association between treatment and days of coma during the intervention period.

Days of Coma.
Placebo
N=184
Haloperidol
N=192
Ziprasidone
N=190
Test Statistic
Days of coma 0.0 1.0 2.0
1.8 ± 2.5
0.0 1.0 2.0
1.6 ± 2.1
0.0 1.0 3.0
1.9 ± 2.5
F2 563=0.33, P=0.72
a b c represent the lower quartile a, the median b, and the upper quartile c for continuous variables. x ± s represents X ± 1 SD.
Test used: Kruskal-Wallis test .

Adjusted Analysis

After adjusting for all baseline covariates, we again see no significant association between treatment and days of coma during the intervention period.

Model Results

We show the odds ratios (using placebo as reference) and adjusted medians for coma duration by treatment group.

Adjusted Medians

Medians are adjusted to the median/mode values of all covariates, so that each represents the expected median number of days with coma for a patient in each treatment group who is otherwise part of a “typical” (many air quotes) population.

Results for All Covariates

Since most of the continuous covariates are modeled using restricted cubic splines (see the Methods section for more details), a single odds ratio/CI is insufficient to describe the entire relationship between each of these covariates and coma duration. Rather, each odds ratio reflects a comparison between two specific values of the covariate, as noted in the table.

Variable Reference Comparison Odds Ratio (95% CI) X2 df P
age_consent 51.36 68.68 1.13 (0.97, 1.31) 18.9 2 <0.001
arousal_rand Deeply sedated Lightly sedated 0.56 (0.38, 0.81) 42.6 3 <0.001
Deeply sedated Normal 0.34 (0.21, 0.56)
Deeply sedated Agitated 0.74 (0.46, 1.21)
charlson_total 1.00 4.00 0.90 (0.64, 1.25) 0.5 2 0.761
frailty 3.00 5.00 0.94 (0.70, 1.26) 0.9 2 0.637
iqcode_total_ph 3.00 3.25 1.04 (0.94, 1.16) 0.6 1 0.424
sofa_mod_imp_rand 4.00 9.00 1.67 (1.18, 2.35) 30.8 2 <0.001
trt Placebo Haloperidol 1.01 (0.74, 1.39) 0.3 2 0.848
Placebo Ziprasidone 1.11 (0.77, 1.61)
All Nonlinear Terms 17.5 4 0.002
Overall Model 478.3 14 <0.001
Model L.R. 42.17
C 0.62
Dxy 0.23
R2 0.08
Observations 553

Time to Death

We explore the association between treatment and time to death from all causes within the 30 and 90 days following randomization.

Censoring and Time to Event

30-Day Mortality

  • The 3 patients who withdrew from the study prior to day 30 with no known death status are censored at the time of withdrawal.
  • The 410 patients who survived the entire 30-day period are censored at day 30.01.
  • The 153 patients who died within the 30-day period are assigned a time value of time of death - time of randomization.

90-Day Mortality

  • The 3 patients who withdrew from the study prior to day 90 with no known death status are censored at the time of withdrawal.
  • The 362 patients who survived the entire 90-day period are censored at day 90.01.
  • The 201 patients who died within the 90-day period are assigned a time value of time of death - time of randomization.

Unadjusted Analysis

Our unadjusted analysis describes survival using Kaplan-Meier curves and tests for differences among treatment groups in time to death within 30 and within 90 days of randomization using the log-rank test. All 566 randomized patients are included.

We see no association between treatment group and death at either 30 or 90 days.

30-Day Death

Kaplan-Meier Estimates, Death at 30 Days after Randomization
Treatment Randomized Still at Risk Died Censored Estimate Lower 95% Upper 95%
Overall 566 410 153 3 0.73 0.69 0.77
Ziprasidone 190 137 53 0 0.72 0.66 0.79
Haloperidol 192 141 50 1 0.74 0.68 0.80
Placebo 184 132 50 2 0.73 0.66 0.79

90-Day Death

Kaplan-Meier Estimates, Death at 90 Days after Randomization
Treatment Randomized Still at Risk Died Censored Estimate Lower 95% Upper 95%
Overall 566 362 201 3 0.64 0.60 0.68
Ziprasidone 190 125 65 0 0.66 0.59 0.73
Haloperidol 192 118 73 1 0.62 0.55 0.69
Placebo 184 119 63 2 0.65 0.59 0.73

Adjusted Analysis

After adjusting for all baseline covariates, we again see no significant association between treatment and time to death within 30 days. We also see no significant association between treatment and time to death within 90 days; the confidence interval for haloperidol vs placebo does come quite close to significance for this time point, which could be worth further investigation.

Model Fitting and Assumptions

We perform multivariable regression analyses using a Cox proportional hazards model to explore the association between treatment group and time to death while adjusting for potential baseline confounders. Please see the Methods section for more details. All 553 randomized patients with complete covariate data are included.

Assumptions, 30-Day Death

We are looking for generally flat lines, indicating consistent hazards over time and paying particular attention to treatment group. For more details, please see the Methods section.

The global test for proportional hazards indicates no major concern (p = 0.89); please see the figures below for further detail.

Assumptions, 90-Day Death

We are looking for generally flat lines, indicating consistent hazards over time and paying particular attention to treatment group. For more details, please see the Methods section.

The global test for proportional hazards indicates no major concern (p = 0.79); please see the figures below for further detail.

Model Results

Results for All Covariates

Since most of the continuous covariates are modeled using restricted cubic splines (see the Methods section for more details), a single hazard ratio/CI is insufficient to describe the entire relationship between each of these covariates and death. Rather, each hazard ratio reflects a comparison between two specific values of the covariate, as noted in the table.

30-Day Death
Variable Reference Comparison Hazard Ratio (95% CI) X2 df P
age_consent 51.36 68.68 1.62 (1.33, 1.98) 32.4 2 <0.001
arousal_rand Deeply sedated Lightly sedated 0.87 (0.66, 1.14) 14.9 3 0.002
Deeply sedated Normal 0.25 (0.10, 0.61)
Deeply sedated Agitated 0.54 (0.30, 0.97)
charlson_total 1.00 4.00 1.23 (0.93, 1.64) 24.2 2 <0.001
frailty 3.00 5.00 1.36 (0.99, 1.85) 4.0 2 0.135
iqcode_total_ph 3.00 3.25 1.09 (0.98, 1.20) 2.5 1 0.115
sofa_mod_imp_rand 4.00 9.00 2.24 (1.20, 4.18) 41.4 2 <0.001
trt Placebo Haloperidol 1.03 (0.73, 1.46) 0.2 2 0.910
Placebo Ziprasidone 1.07 (0.77, 1.47)
All Nonlinear Terms 24.0 4 <0.001
Overall Model 1083.1 14 <0.001
Model L.R. 115.96
Dxy 0.50
R2 0.20
Observations 553
Events 146
90-Day Death
Variable Reference Comparison Hazard Ratio (95% CI) X2 df P
age_consent 51.36 68.68 1.70 (1.42, 2.02) 58.3 2 <0.001
arousal_rand Deeply sedated Lightly sedated 0.85 (0.61, 1.19) 7.0 3 0.072
Deeply sedated Normal 0.33 (0.13, 0.82)
Deeply sedated Agitated 0.60 (0.34, 1.07)
charlson_total 1.00 4.00 1.28 (0.98, 1.66) 32.3 2 <0.001
frailty 3.00 5.00 1.36 (1.08, 1.70) 9.4 2 0.009
iqcode_total_ph 3.00 3.25 1.06 (0.97, 1.16) 1.8 1 0.185
sofa_mod_imp_rand 4.00 9.00 1.80 (1.22, 2.64) 73.7 2 <0.001
trt Placebo Haloperidol 1.17 (0.99, 1.40) 3.5 2 0.176
Placebo Ziprasidone 1.02 (0.79, 1.30)
All Nonlinear Terms 15.8 4 0.003
Overall Model 3211.3 14 <0.001
Model L.R. 130.93
Dxy 0.47
R2 0.21
Observations 553
Events 194

Time to Successful ICU Discharge

We use time to event analysis with competing risks to explore the relationship between treatment group and “successful” ICU discharge, defined as the final ICU discharge from the study hospitalization, followed by at least 48 hours alive. We treat death as a competing risk, and look at successful ICU discharge up to 90 days after randomization.

Censoring and time to events:

  • We censor at the time of study withdrawal 3 patients who withdrew from the study prior to hospital discharge, with no discharge or death information available.
  • We censor at day 90.01 2 patients who survived the entire 90-day period but remained in the ICU on day 90.
  • We assign the 131 patients who died prior to ICU discharge within the 90-day period a time value of time of death - time of randomization and a “failure type” of death; we assign the 430 patients who were successfully discharged within the 90-day period a time value of time of discharge - time of randomization and a “failure type” of ICU discharge.

Unadjusted Analysis

We present cumulative incidence plots by treatment group for both ICU discharge and death, unadjusted for any covariates. Please see the Methods section for more details. All 566 randomized patients are included.

We see no association between treatment and time to either ICU discharge or the competing risk of death.

## -- Create Surv object -------------------------------------------------------
## Will be used for N at risk for CIF, as well as adjusted model fit
icudis_90_Surv <- with(model_df, {
  Surv(time = tte_icudis_90, event = ftype_icudis_90, type = "mstate")
})

## -- Create and summarize survfit object, create N at risk table --------------
icudis_90_survfit <- survfit(icudis_90_Surv ~ trt, data = model_df)
icudis_90_sfsum <- summary(icudis_90_survfit, times = seq(0, 90, 15))

# ## Double-check placebo
# icudis_90_sfsum_detailed <- summary(icudis_90_survfit, times = seq(0, 90, 1))
# summary(subset(model_df, trt == "Placebo")$tte_icudis_90)

icudis_90_risk_plot <- cr_risktable_plot(
  icudis_90_sfsum,
  main_event = "ICU Discharge",
  event_string = "ICU discharges"
)

## -- Fit cumulative incidence functions by treatment --------------------------
icudis_90_cif <- with(model_df, {
  cuminc(
    ftime = tte_icudis_90,
    fstatus = ftype_icudis_90,
    group = trt,
    cencode = "Censored"
  )
})

## Create strings for test results
icudis_90_tests_unadj <- cuminc_test(icudis_90_cif)

## -- Plot CIFs, N at risk -----------------------------------------------------
## Create plot for competing risks
icudis_90_cif_plot <- create_cif_manual(
  cuminc_obj = icudis_90_cif,
  main_event = "ICU Discharge",
  event_string = "Successful ICU Discharge",
  test_string = icudis_90_tests_unadj,
  caption_string = '"Successful" is defined as final ICU discharge followed by at least 48 hours alive.'
)

## Print combined plot
cr_combine_plots(
  cif = icudis_90_cif_plot,
  rt = icudis_90_risk_plot,
  xmax = 91, time_breaks = seq(0, 90, 15),
  caption_string = '"Successful" is defined as final ICU discharge followed by at least 48 hours alive.'
)

Adjusted Analysis

After adjusting for baseline covariates, we still see no significant association between treatment and relative incidence of ICU discharge.

Model Fitting and Assumptions

We use Fine & Gray’s4 method of competing risks regression to examine the relationship between treatment and (primarily) ICU discharge. For further details, please see the Methods section. All 553 randomized patients with complete covariate data are included.

Assumptions

We graphically check our assumption of proportional hazards for the ICU discharge subdistribution, paying particular attention to treatment group and looking for generally flat lines in each panel. The global test for proportional hazards indicates the assumption is not fully met (p: <0.0001); please see the figures below for further detail.

Model Results

We show the subdistribution hazard ratios for ICU discharge for haloperidol and ziprasidone vs placebo. Subdistribution hazard ratios higher than 1 are favorable for this outcome. For example, an HR of 0.95 for Haloperidol vs placebo indicates that, on average, patients in the Haloperidol group have a 5% lower relative incidence of ICU discharge vs patients in the Placebo group, given that they have not yet experienced the outcome of interest.

Results for All Covariates

Since most of the continuous covariates are modeled using restricted cubic splines (see the Methods section for more details), a single subdistribution hazard ratio/CI is insufficient to describe the entire relationship between each of these covariates and the relative incidence of ICU discharge. Rather, each subdistribution hazard ratio reflects a comparison between two specific values of the covariate, as noted in the table.

Variable Reference Comparison Hazard Ratio (95% CI) X2 df P
age_consent 51.36 68.68 0.79 (0.69, 0.90) 17.0 2 <0.001
arousal_rand Deeply sedated Lightly sedated 1.11 (0.89, 1.39) 8.6 3 0.034
Deeply sedated Normal 1.61 (1.16, 2.22)
Deeply sedated Agitated 1.40 (0.93, 2.12)
charlson_total 1.00 4.00 1.06 (0.92, 1.23) 3.8 2 0.151
frailty 3.00 5.00 0.85 (0.75, 0.97) 6.3 2 0.043
iqcode_total_ph 3.00 3.25 1.00 (0.95, 1.06) 0.0 1 0.998
sofa_mod_imp_rand 4.00 9.00 0.59 (0.47, 0.74) 45.0 2 <0.001
trt Placebo Haloperidol 0.95 (0.81, 1.12) 1.1 2 0.572
Placebo Ziprasidone 1.02 (0.88, 1.17)
All Nonlinear Terms 15.6 4 0.004
Overall Model 363.7 14 <0.001
Model L.R. 81.44
Dxy 0.24
R2 0.11
Observations 719
Events 424

Time to Successful Hospital Discharge

We use time to event analysis with competing risks to explore the relationship between treatment group and “successful” hospital discharge, defined as discharge from the study hospitalization, followed by at least 48 hours alive. We treat death as a competing risk, and look at successful hospital discharge up to 90 days after randomization.

Censoring and time to events:

  • We censor at the time of study withdrawal 3 patients who withdrew from the study prior to hospital discharge, with no discharge or death information available.
  • We censor at day 90.01 6 patients who survived the entire 90-day period but remained hospitalized on day 90.
  • We assign the 157 patients who died prior to ICU discharge within the 90-day period a time value of time of death - time of randomization and a “failure type” of death; we assign the 400 patients who were successfully discharged within the 90-day period a time value of time of discharge - time of randomization and a “failure type” of hospital discharge.

Unadjusted Analysis

We present cumulative incidence plots by treatment group for both hospital discharge and death, unadjusted for any covariates. Please see the Methods section for more details. All 566 randomized patients are included.

We see no association between treatment and time to successful hospital discharge.

## -- Create Surv object -------------------------------------------------------
## Will be used for N at risk for CIF, as well as adjusted model fit
hospdis_90_Surv <- with(model_df, {
  Surv(time = tte_hospdis_90, event = ftype_hospdis_90, type = "mstate")
})

## -- Create and summarize survfit object, create N at risk table --------------
hospdis_90_survfit <- survfit(hospdis_90_Surv ~ trt, data = model_df)
hospdis_90_sfsum <- summary(hospdis_90_survfit, times = seq(0, 90, 15))

hospdis_90_risk_plot <- cr_risktable_plot(
  hospdis_90_sfsum,
  main_event = "Hospital Discharge",
  event_string = "hospital discharges"
)

## -- Fit cumulative incidence functions by treatment --------------------------
hospdis_90_cif <- with(model_df, {
  cuminc(
    ftime = tte_hospdis_90,
    fstatus = ftype_hospdis_90,
    group = trt,
    cencode = "Censored"
  )
})

## Create strings for test results
hospdis_90_tests_unadj <- cuminc_test(hospdis_90_cif)

## -- Plot CIFs, N at risk -----------------------------------------------------
## Create plot for competing risks
hospdis_90_cif_plot <- create_cif_manual(
  cuminc_obj = hospdis_90_cif,
  main_event = "Hospital Discharge",
  event_string = "Successful Hospital Discharge",
  test_string = hospdis_90_tests_unadj,
  caption_string = '"Successful" is defined as hospital discharge followed by at least 48 hours alive.'
)

## Print combined plot
cr_combine_plots(
  cif = hospdis_90_cif_plot,
  rt = hospdis_90_risk_plot,
  xmax = 91, time_breaks = seq(0, 90, 15),
  caption_string = '"Successful" is defined as hospital discharge followed by at least 48 hours alive.'
)

Adjusted Analysis

After adjusting for baseline covariates, we still see no significant association between treatment and relative incidence of successful hospital discharge.

Model Fitting and Assumptions

We use Fine & Gray’s5 method of competing risks regression to examine the relationship between treatment and (primarily) hospital discharge. For further details, please see the Methods section. All 553 randomized patients with complete covariate data are included.

Assumptions

We graphically check our assumption of proportional hazards for the hospital discharge subdistribution, paying particular attention to treatment group and looking for generally flat lines in each panel. The global test for proportional hazards indicates the assumption is not fully met (p: 0.003); please see the figures below for further detail.

Model Results

We show the subdistribution hazard ratios for hospital discharge for haloperidol and ziprasidone vs placebo. Subdistribution hazard ratios higher than 1 are favorable for this outcome. For example, an HR of 1.03 for Haloperidol vs placebo indicates that, on average, patients in the Haloperidol group have a 3% higher relative incidence of hospital discharge vs patients in the Placebo group, given that they have not yet experienced the outcome of interest.

Results for All Covariates

Since most of the continuous covariates are modeled using restricted cubic splines (see the Methods section for more details), a single subdistribution hazard ratio/CI is insufficient to describe the entire relationship between each of these covariates and the relative incidence of hospital discharge. Rather, each subdistribution hazard ratio reflects a comparison between two specific values of the covariate, as noted in the table.

Variable Reference Comparison Hazard Ratio (95% CI) X2 df P
age_consent 51.36 68.68 0.74 (0.64, 0.85) 23.0 2 <0.001
arousal_rand Deeply sedated Lightly sedated 1.20 (1.01, 1.43) 11.6 3 0.009
Deeply sedated Normal 1.79 (1.27, 2.54)
Deeply sedated Agitated 1.34 (0.92, 1.95)
charlson_total 1.00 4.00 1.03 (0.87, 1.21) 18.6 2 <0.001
frailty 3.00 5.00 0.80 (0.69, 0.92) 11.9 2 0.003
iqcode_total_ph 3.00 3.25 1.01 (0.94, 1.08) 0.1 1 0.792
sofa_mod_imp_rand 4.00 9.00 0.57 (0.46, 0.71) 70.6 2 <0.001
trt Placebo Haloperidol 1.03 (0.85, 1.23) 0.3 2 0.879
Placebo Ziprasidone 1.05 (0.88, 1.25)
All Nonlinear Terms 40.6 4 <0.001
Overall Model 1017.9 14 <0.001
Model L.R. 108.11
Dxy 0.30
R2 0.16
Observations 639
Events 394

Time to Successful Liberation from Mechanical Ventilation

We use time to event analysis with competing risks to explore the relationship between treatment group and “successful” liberation from mechanical ventilation, defined as discontinuation of all types of MV followed by at least 48 hours alive and without reinitiation of MV, during the 30 days following randomization. We treat death and hospital discharge without liberation during this time as separate competing risks.

Censoring and time to events:

  • We censor at the time of study withdrawal 3 patients who withdrew from the study prior to hospital discharge, with no discharge or death information available.
  • We censor at day 30.01 19 patients who survived the entire 30-day period after randomization, but remained hospitalized on day 30.
  • We assign patients who experience the competing risks of either hospital discharge (22 patients) or death (87 patients) prior to 30 days a time to event of time of discharge/death - time of randomization and a “failure type” of hospital discharge and death, respectively.
  • We assign the 396 patients who were successfully liberated from MV within 30 days of randomization a time value of time of liberation - time of randomization and a “failure type” of liberation from MV.

Unadjusted Analysis

We present cumulative incidence plots by treatment group for both liberation from MV and death, unadjusted for any covariates. Please see the Methods section for more details. All 527 randomized patients who were on MV within 24 hours after randomization are included.

We see no association between treatment and time to successful liberation from mechanical ventilation.

## Prep: Smaller df including only patients on MV within 24h of randomization
model_df_mv <- model_df %>% filter(on_mv_rand24)

## -- Create Surv object -------------------------------------------------------
## Will be used for N at risk for CIF, as well as adjusted model fit
mvlib_30_Surv <- with(model_df_mv, {
  Surv(time = tte_mvlib_30, event = ftype_mvlib_30, type = "mstate")
})

## -- Create and summarize survfit object, create N at risk table --------------
mvlib_30_survfit <- survfit(mvlib_30_Surv ~ trt, data = model_df_mv)
mvlib_30_sfsum <- summary(mvlib_30_survfit, times = c(0, seq(5, 30, 5)))

mvlib_30_risk_plot <- cr_risktable_plot(
  mvlib_30_sfsum,
  main_event = "MV Liberation",
  event_string = "liberations from MV"
)

## -- Fit cumulative incidence functions by treatment --------------------------
mvlib_30_cif <- with(model_df_mv, {
  cuminc(
    ftime = tte_mvlib_30,
    fstatus = ftype_mvlib_30,
    group = trt,
    cencode = "Censored"
  )
})

## Create strings for test results
mvlib_30_tests_unadj <- cuminc_test(mvlib_30_cif)

## -- Plot CIFs, N at risk -----------------------------------------------------
## Create plot for competing risks
mvlib_30_cif_plot <- create_cif_manual(
  cuminc_obj = mvlib_30_cif,
  main_event = "MV Liberation",
  event_string = "Successful Liberation from MV",
  test_string = mvlib_30_tests_unadj,
  caption_string = '"Successful" is defined as discontinuation of MV, followed by at least 48 hours alive without reinitiation.'
)

## Print combined plot
cr_combine_plots(
  cif = mvlib_30_cif_plot,
  rt = mvlib_30_risk_plot,
  xmax = 31, time_breaks = c(0, seq(5, 30, 5)),
  caption_string = '"Successful" is defined as discontinuation of MV, followed by at least 48 hours alive without reinitiation.'
)

Adjusted Analysis

After adjusting for baseline covariates, we still see no significant association between treatment and relative incidence of liberation from MV.

Model Fitting and Assumptions

We use Fine & Gray’s6 method of competing risks regression to examine the relationship between treatment and (primarily) successful liberation from MV. For further details, please see the Methods section. All 516 randomized patients with complete covariate data who received MV within 24 hours after randomization are included.

Assumptions

We graphically check our assumption of proportional hazards for the MV liberation subdistribution, paying particular attention to treatment group and looking for generally flat lines in each panel. The global test for proportional hazards indicates the assumption is not fully met (p: 0.01); please see the figures below for further detail.

Model Results

We show the subdistribution hazard ratios for hospital discharge for haloperidol and ziprasidone vs placebo. Subdistribution hazard ratios higher than 1 are favorable for this outcome. For example, an HR of 0.92 for Haloperidol vs placebo indicates that, on average, patients in the Haloperidol group have a 8% lower relative incidence of liberation from MV vs patients in the Placebo group, given that they have not yet experienced the outcome of interest.

Results for All Covariates

Since most of the continuous covariates are modeled using restricted cubic splines (see the Methods section for more details), a single subdistribution hazard ratio/CI is insufficient to describe the entire relationship between each of these covariates and the relative incidence of liberation from MV. Rather, each subdistribution hazard ratio reflects a comparison between two specific values of the covariate, as noted in the table.

Variable Reference Comparison Hazard Ratio (95% CI) X2 df P
age_consent 51.36 68.68 0.87 (0.78, 0.97) 18.6 2 <0.001
arousal_rand Deeply sedated Lightly sedated 1.25 (1.10, 1.43) 23.7 3 <0.001
Deeply sedated Normal 1.42 (0.95, 2.14)
Deeply sedated Agitated 1.29 (0.92, 1.81)
charlson_total 1.00 4.00 1.22 (1.06, 1.41) 8.1 2 0.017
frailty 3.00 5.00 0.81 (0.69, 0.94) 7.9 2 0.019
iqcode_total_ph 3.00 3.25 0.97 (0.90, 1.05) 0.6 1 0.450
sofa_mod_imp_rand 4.00 9.00 0.67 (0.53, 0.85) 56.8 2 <0.001
trt Placebo Haloperidol 0.92 (0.71, 1.19) 0.4 2 0.807
Placebo Ziprasidone 0.96 (0.74, 1.25)
All Nonlinear Terms 13.5 4 0.009
Overall Model 524.4 14 <0.001
Model L.R. 46.51
Dxy 0.20
R2 0.08
Observations 586
Events 391

Time to ICU Readmission

We use time to event analysis with competing risks to explore the relationship between treatment group and readmission to the ICU within 90 days of first discharge during the index hospitalization, among the 497 patients who survived their first ICU stay and remained in the study. We treat death and hospital discharge without readmission during this time as separate competing risks.

Although the question of how many times each patient was readmitted is also of interest, we had so few patients who were readmitted >1 time (12, or 2%) that it was not feasible to address this specific issue.

Censoring and time to events:

  • We planned to censor at the time of study withdrawal patients who withdrew from the study prior to hospital discharge with no discharge or death information available, but 0 patients met this criteria.
  • We censored at day 90.01 1 patient(s) who survived the entire 90-day period after initial discharge, but remained hospitalized on day 90.
  • We assign patients who experience the competing risks of either hospital discharge (360 patients) or death (68 patients) prior to 90 days after first ICU discharge a time to event of time of discharge/death - time of randomization and a “failure type” of hospital discharge and death, respectively.
  • We assign the 68 patients who were readmitted to the ICU within 90 days of first discharge a time value of time of readmission - time of first ICU discharge and a “failure type” of readmission.

Unadjusted Analysis

We present cumulative incidence plots by treatment group for ICU readmission, hospital discharge without readmission, and death, unadjusted for any covariates. Please see the Methods section for more details. All 497 randomized patients who survived their initial ICU admission and remained in the study are included.

We see no association between treatment group and rates of ICU readmission during the index hospitalization among those patients who were discharged alive from their first ICU stay.

## Prep: Smaller df including only patients who survived first ICU stay
model_df_readm <- model_df %>% filter(elig_readm)

## -- Create Surv object -------------------------------------------------------
## Will be used for N at risk for CIF, as well as adjusted model fit
readm_90_Surv <- with(model_df_readm, {
  Surv(time = tte_readm_90, event = ftype_readm_90, type = "mstate")
})

## -- Create and summarize survfit object, create N at risk table --------------
readm_90_survfit <- survfit(readm_90_Surv ~ trt, data = model_df_readm)
readm_90_sfsum <- summary(readm_90_survfit, times = seq(0, 90, 15))

readm_90_risk_plot <- cr_risktable_plot(
  readm_90_sfsum,
  main_event = "Readmission",
  event_string = "ICU readmissions"
)

## -- Fit cumulative incidence functions by treatment --------------------------
readm_90_cif <- with(model_df_readm, {
  cuminc(
    ftime = tte_readm_90,
    fstatus = ftype_readm_90,
    group = trt,
    cencode = "Censored"
  )
})

## Create strings for test results
readm_90_tests_unadj <- cuminc_test(readm_90_cif)

## -- Plot CIFs, N at risk -----------------------------------------------------
## Create plot for competing risks
readm_90_cif_plot <- create_cif_manual(
  cuminc_obj = readm_90_cif,
  main_event = "Readmission",
  event_string = "ICU Readmission",
  test_string = readm_90_tests_unadj,
  caption_string = ''
)

## Print combined plot
cr_combine_plots(
  cif = readm_90_cif_plot,
  rt = readm_90_risk_plot,
  xmax = 91, time_breaks = c(0, seq(5, 90, 15)),
  caption_string = 'Note: This outcome is only measured among patients who survived their first ICU stay.'
)

Adjusted Analysis

We see no significant relationship between treatment group and ICU readmission rate during the index hospitalization.

Model Fitting and Assumptions

We use Fine & Gray’s7 method of competing risks regression to examine the relationship between treatment and (primarily) ICU readmission. For further details, please see the Methods section. All 489 randomized patients with complete covariate data who survived their first ICU stay and remained in the study are included.

Assumptions

Due to only a single patient being censored, the interaction between transformed time and Schoenfeld residuals could not be properly calculated. We instead look at the log(-log(Survival time)) vs log(time) for treatment groups only, looking for parallel lines which indicate that the proportional hazards assumption is met. We do not calculate a p-value.

Model Results

We show the subdistribution hazard ratios for ICU readmission for haloperidol and ziprasidone vs placebo. Subdistribution hazard ratios lower than 1 are favorable for this outcome. For example, an HR of 1.13 for Haloperidol vs placebo indicates that, on average, patients in the Haloperidol group have a 13% higher relative incidence of ICU readmission vs patients in the Placebo group, given that they have not yet experienced the outcome of interest.

Results for All Covariates

Since most of the continuous covariates are modeled using restricted cubic splines (see the Methods section for more details), a single subdistribution hazard ratio/CI is insufficient to describe the entire relationship between each of these covariates and the relative incidence of ICU readmission. Rather, each subdistribution hazard ratio reflects a comparison between two specific values of the covariate, as noted in the table.

Variable Reference Comparison Hazard Ratio (95% CI) X2 df P
age_consent 51.36 68.68 1.21 (0.93, 1.57) 2.3 2 0.323
arousal_rand Deeply sedated Lightly sedated 1.16 (0.67, 2.01) 2.9 3 0.415
Deeply sedated Normal 1.51 (0.53, 4.35)
Deeply sedated Agitated 0.69 (0.33, 1.42)
charlson_total 1.00 4.00 0.91 (0.60, 1.39) 4.0 2 0.136
frailty 3.00 5.00 1.07 (0.75, 1.54) 0.6 2 0.724
iqcode_total_ph 3.00 3.25 0.96 (0.91, 1.02) 1.9 1 0.171
sofa_mod_imp_rand 4.00 9.00 1.28 (0.76, 2.14) 2.8 2 0.246
trt Placebo Haloperidol 1.13 (0.62, 2.09) 6.2 2 0.044
Placebo Ziprasidone 0.73 (0.49, 1.10)
All Nonlinear Terms 8.5 4 0.074
Overall Model 236.2 14 <0.001
Model L.R. 12.94
Dxy 0.27
R2 0.03
Observations 489
Events 67

Summary of All Primary Outcomes

descrip_continuous <- inhosp_desc_df %>%
  group_by(trt) %>%
  summarise_at(
    vars(dcfd_int, del_int_all, coma_int_all, hyperdel_int_all,
         hypodel_int_all, daysto_mvlib_exp, tte_icudis_90_exp,
         tte_hospdis_90_exp),
    funs(med = q50, p25 = q25, p75 = q75)
  ) %>%
  gather(key = variable, value = value, dcfd_int_med:tte_hospdis_90_exp_p75) %>%
  separate(
    variable, into = c("variable", "stat"), sep = "\\_(?=[a-z, 0-9]+$)"
  ) %>%
  spread(key = stat, value = value) %>%
  mutate(
    desc_string = gsub(
      " +", " ",
      sprintf(
        "%s [%s, %s]",
        rndformat(med, digits = 1),
        rndformat(p25, digits = 1),
        rndformat(p75, digits = 1)
      )
    )
  ) %>%
  dplyr::select(trt, variable, desc_string) %>%
  spread(key = trt, value = desc_string) %>%
  mutate(
    version = "Unadjusted",
    pvalue = c(
      coma_kw$p.value,
      mvlib_30_cif$Tests["MV Liberation", "pv"],
      dcfd_kw$p.value,
      del_kw$p.value,
      hyperdel_kw$p.value,
      hypodel_kw$p.value,
      hospdis_90_cif$Tests["Hospital Discharge", "pv"],
      icudis_90_cif$Tests["ICU Discharge", "pv"]
    )
  )

descrip_npct <- ptsummary_df %>%
  group_by(trt) %>%
  summarise_at(
    vars(randomized, event_readm_90, event_death_30, event_death_90),
    funs(sum_na)
  ) %>%
  mutate_at(vars(starts_with("event")), funs(get_npct), denom = .$randomized) %>%
  gather(key = variable, value = npct, starts_with("event")) %>%
  mutate(variable = gsub("^event\\_", "", variable)) %>%
  dplyr::select(-randomized) %>%
  spread(key = trt, value = npct) %>%
  mutate(
    version = "Unadjusted",
    pvalue = c(
      1 - pchisq(logrank_death_30$chisq, df = 2),
      1 - pchisq(logrank_death_90$chisq, df = 2),
      readm_90_cif$Tests["Readmission", "pv"]
    )
  )

orshrs <- bind_rows(
  list(dcfd_ors, del_ors, hyperdel_ors, hypodel_ors, coma_ors,
       mvlib_30_hrs %>% mutate(outcome = "mvlib_30"),
       icudis_90_hrs %>% mutate(outcome = "icudis_90"),
       readm_90_hrs %>% mutate(outcome = "readm_90"),
       hospdis_90_hrs %>% mutate(outcome = "hospdis_90"),
       death_30_hrs, death_90_hrs)
) %>%
  filter(!is.ref) %>%
  mutate(
    ratio_ci = sprintf(
      "%s (%s, %s)", rndformat(effect, 2), rndformat(lcl, 2), rndformat(ucl, 2)
    )
  ) %>%
  dplyr::select(outcome, comp.c, ratio_ci) %>%
  spread(key = comp.c, value = ratio_ci) %>%
  mutate(Placebo = "") %>%
  dplyr::select(outcome, Placebo, Haloperidol, Ziprasidone) %>%
  set_names(c("variable", "Placebo", "Haloperidol", "Ziprasidone")) %>%
  mutate(
    version = "Adjusted",
    pvalue = map_dbl(
      list(coma_mod, dcfd_mod, del_mod, hospdis_90_mod, hyperdel_mod,
           hypodel_mod, icudis_90_mod, mvlib_30_mod, readm_90_mod,
           death_30_mod, death_90_mod),
      ~ anova(.)["trt", "P"]
    )
  )

descriptives <- bind_rows(descrip_continuous, descrip_npct, orshrs) %>%
  mutate(
    variable = case_when(
      variable == "daysto_mvlib_exp" ~ "mvlib_30",
      variable == "tte_hospdis_90_exp" ~ "hospdis_90",
      variable == "tte_icudis_90_exp" ~ "icudis_90",
      TRUE ~ gsub("^surv\\_", "", variable)
    )
  ) %>%
  dplyr::select(
    variable, version, Placebo, Haloperidol, Ziprasidone, pvalue
  ) %>%
  ## Make pretty for printing
  mutate(
    sort_order = case_when(
      variable == "coma_int_all"     ~ 5,
      variable == "dcfd_int"         ~ 1,
      variable == "death_30"         ~ 10,
      variable == "death_90"         ~ 11,
      variable == "del_int_all"      ~ 2,
      variable == "hospdis_90"       ~ 9,
      variable == "hyperdel_int_all" ~ 3,
      variable == "hypodel_int_all"  ~ 4,
      variable == "icudis_90"        ~ 7,
      variable == "mvlib_30"         ~ 6,
      variable == "readm_90"         ~ 8,
      TRUE                           ~ 12
    ),
    variable = case_when(
      variable == "coma_int_all"     ~ "Coma days",
      variable == "dcfd_int"         ~ "Delirium/coma-free days",
      variable == "death_30"         ~ "Mortality at 30 days - no. (%)",
      variable == "death_90"         ~ "Mortality at 90 days - no. (%)",
      variable == "del_int_all"      ~ "Delirium days",
      variable == "hospdis_90"       ~ "Time to hospital discharge",
      variable == "hyperdel_int_all" ~ "Hyperactive delirium days",
      variable == "hypodel_int_all"  ~ "Hypoactive delirium days",
      variable == "icudis_90"        ~ "Time to ICU discharge",
      variable == "mvlib_30"         ~
        "Time to liberation from mechanical ventilation",
      variable == "readm_90"         ~ "ICU readmission - no. (%)",
      TRUE                           ~ "fix this!"
    ),
    pvalue = formatp_nejm(pvalue)
  ) %>%
  arrange(sort_order, desc(version)) %>%
  dplyr::select(variable, version, Placebo, Haloperidol, Ziprasidone, pvalue)

kable(
  descriptives,
  format = "html",
  align = c("l", "l", rep("r", 4)),
  col.names = c(
    "Outcome", "Version", "Placebo", "Haloperidol", "Ziprasidone", "P-Value*"
  ),
  caption = "Summary of Primary Outcomes"
) %>%
  collapse_rows(columns = 1) %>%
  mykablestyle() %>%
  add_footnote(
    c(
      "For unadjusted analyses, results are median [interquartile range] for each treatment group unless otherwise indicated. P-values for overall difference in treatment are from Kruskal-Wallis (DCFDs, delirium, coma), log-rank (death) or score (all other outcomes) tests.",
      "For adjusted analyses, results are odds or hazard ratios, with placebo as reference. P-values for the overall effect of treatment are from proportional odds logistic regression (DCFDs, delirium, coma), Cox proportional hazards regression (death), or Fine-Gray competing risks regression (all other outcomes)."),
    notation = "number"
  )
Summary of Primary Outcomes
Outcome Version Placebo Haloperidol Ziprasidone P-Value*
Delirium/coma-free days Unadjusted 7.0 [0.0, 11.2] 8.0 [0.0, 11.0] 8.0 [2.0, 11.0] 0.69
Adjusted 0.88 (0.64, 1.21) 1.04 (0.73, 1.48) 0.26
Delirium days Unadjusted 4.0 [2.0, 8.0] 4.0 [2.0, 7.0] 4.0 [2.0, 6.0] 0.84
Adjusted 1.12 (0.86, 1.46) 1.02 (0.69, 1.51) 0.46
Hyperactive delirium days Unadjusted 0.0 [0.0, 1.0] 0.0 [0.0, 1.0] 0.0 [0.0, 1.0] 0.64
Adjusted 1.18 (0.86, 1.61) 1.09 (0.70, 1.70) 0.58
Hypoactive delirium days Unadjusted 3.0 [2.0, 8.0] 4.0 [2.0, 6.0] 3.0 [2.0, 6.0] 0.92
Adjusted 1.10 (0.81, 1.48) 1.00 (0.68, 1.47) 0.62
Coma days Unadjusted 1.0 [0.0, 2.0] 1.0 [0.0, 2.0] 1.0 [0.0, 3.0] 0.72
Adjusted 1.01 (0.74, 1.39) 1.11 (0.77, 1.61) 0.85
Time to liberation from mechanical ventilation Unadjusted 2.7 [1.1, 4.9] 2.0 [0.9, 5.5] 2.7 [1.5, 4.6] 0.99
Adjusted 0.92 (0.71, 1.19) 0.96 (0.74, 1.25) 0.81
Time to ICU discharge Unadjusted 5.2 [3.0, 13.6] 5.2 [2.9, 12.6] 5.2 [2.9, 9.7] 0.93
Adjusted 0.95 (0.81, 1.12) 1.02 (0.88, 1.17) 0.57
ICU readmission - no. (%) Unadjusted 23 (12%) 27 (14%) 18 (9%) 0.31
Adjusted 1.13 (0.62, 2.09) 0.73 (0.49, 1.10) 0.04
Time to hospital discharge Unadjusted 12.9 [8.4, 23.1] 13.3 [7.9, 21.5] 11.6 [7.9, 21.2] 0.71
Adjusted 1.03 (0.85, 1.23) 1.05 (0.88, 1.25) 0.88
Mortality at 30 days - no. (%) Unadjusted 50 (27%) 50 (26%) 53 (28%) 0.96
Adjusted 1.03 (0.73, 1.46) 1.07 (0.77, 1.47) 0.91
Mortality at 90 days - no. (%) Unadjusted 63 (34%) 73 (38%) 65 (34%) 0.74
Adjusted 1.17 (0.99, 1.40) 1.02 (0.79, 1.30) 0.18
1 For unadjusted analyses, results are median [interquartile range] for each treatment group unless otherwise indicated. P-values for overall difference in treatment are from Kruskal-Wallis (DCFDs, delirium, coma), log-rank (death) or score (all other outcomes) tests.
2 For adjusted analyses, results are odds or hazard ratios, with placebo as reference. P-values for the overall effect of treatment are from proportional odds logistic regression (DCFDs, delirium, coma), Cox proportional hazards regression (death), or Fine-Gray competing risks regression (all other outcomes).

Heterogeneity of Treatment Effect


Our goal in this section is to determine whether there is any difference in the association between treatment and each outcome depending on any of the following baseline factors:

  1. Age at study consent
  2. Severity of illness at randomization, measured by modified SOFA
  3. Preexisting cognitive impairment, measured by IQCODE
  4. Medical vs surgical admission reason
  5. Sepsis/septic shock at ICU admission

Detailed definitions for each of these potential modifiers of treatment effect will be included with each section, if needed.

Severity of Illness at Randomization

“Severity of illness” is here defined as the SOFA score for each patient on the day of randomization to study drug (excluding the SOFA’s central nervous system component). For further details on how the SOFA was calculated, please see below. Modified SOFA is included as a continuous variable in both the main effect and interaction terms of each model, using restricted cubic splines to allow a nonlinear association between it and each outcome. For purposes of interpretation, we present the relationships between treatment and outcome adjusted to the 10th, 25th, 50th, 75th, and 90th percentiles of modified SOFA in our randomized cohort.

## -- Create model RHS ---------------------------------------------------------
mod_rhs_sofa <- map_chr(
  setdiff(
    cont_covars, "sofa_mod_imp_rand"), ~ sprintf("rcs(%s, %s)", ., rcsknots)
) %>%
  c(., setdiff(notcont_covars, "trt")) %>%
  c(., sprintf("rcs(sofa_mod_imp_rand, %s) * trt", rcsknots)) %>%
  paste(collapse = " + ")

## -- Create dataset of values to use when calculating conditional medians -----
## Use same values (median/mode) for everything except treatment and age
## Applies to all mental status outcomes

## Specify SOFA values
vals_sofa <- quantile(
  model_df$sofa_mod_imp_rand, probs = em_quants, na.rm = TRUE
)

## Determine spline terms for these, based on model_df
## ** This will need to be changed if we increase to >3 knots **
sofa_knots <- rcspline.eval(
  model_df$sofa_mod_imp_rand, nk = rcsknots, knots.only = TRUE
)
vals_sofa_rcs <- rcspline.eval(vals_sofa, knots = sofa_knots, inclx = TRUE) %>%
  as.data.frame() %>%
  set_names(c("sofa_mod_imp_rand", "sofa_mod_imp_rand_2"))

## Get matrix of treatment indicators:
##  Could not get the contrasts argument of model.matrix() to give me placebo
##  as reference. Create by hand.
trt_matrix_sofa <- bind_rows(
  ## Get treatment indicator values, repeat as needed given vals_age
  rep(
    list(as.data.frame(contr.treatment(levels(model_df$trt), base = 1))),
    nrow(vals_sofa_rcs)
  )
) %>%
  ## Sort to group all placebo, haloperidol, ziprasidone rows together
  arrange(Ziprasidone, Haloperidol)

## Replace SOFA columns in pred_df_org with updated SOFA values
pred_df_sofa_prep <- pred_df_org %>%
  dplyr::select(-starts_with("sofa_mod_imp_rand")) %>%
  bind_rows(rep(list(.), nrow(vals_sofa_rcs) - 1)) %>%
  bind_cols(vals_sofa_rcs)

## Repeat those values for each treatment
pred_df_sofa <- rep(list(pred_df_sofa_prep), length(levels(model_df$trt))) %>%
  bind_rows() %>%
  ## Add treatment levels to dataset
  bind_cols(trt = rep(levels(model_df$trt), nrow(pred_df_sofa_prep))) %>%
  
  ## Create a model.matrix object, then leave out the intercept
  ##   model.matrix() handles dummy variables for categoricals nicely
  model.matrix(
    as.formula(sprintf("~ %s", paste(names(.), collapse = " + "))),
    .
  ) %>%
  ## Could not get the contrasts argument to give me placebo as reference.
  ## Wrangle this thing by hand.
  as.data.frame() %>%
  ## Remove intercept, original treatment columns
  dplyr::select(-1, -starts_with("trt")) %>%
  ## Add my own treatment columns, created above
  bind_cols(trt_matrix_sofa) %>%
  
  ## Create interaction values
  mutate(
    sofa_halop = sofa_mod_imp_rand * Haloperidol,
    sofa2_halop = sofa_mod_imp_rand_2 * Haloperidol,
    sofa_zipras = sofa_mod_imp_rand * Ziprasidone,
    sofa2_zipras = sofa_mod_imp_rand_2 * Ziprasidone
  )

For most outcomes, associations between treatment and outcome are generally consistent regardless of severity of illness at randomization; for example, though the sickest patients tend to have the fewest days alive and free of delirium and coma as a group, the median DCFDs for each treatment group still overlap considerably at each level of modified SOFA presented, indicating no difference in the effect of treatment on this outcome.

The single exception is 90-day mortality, where haloperidol seems to be associated with a higher rate of death for patients with moderate severity of illness. Given the lack of overall association between treatment and mortality, and the lack of effect modification between SOI and treatment for 30-day mortality, this should be interpreted with caution, and together with 12-month mortality results when follow-up assessments are complete.

Mental Status Outcomes

Medians are adjusted to the median/mode values of all covariates except modified SOFA and treatment, so that each represents the expected median number of DCFDs (for example) for a patient in each treatment group who is otherwise part of a “typical” (many air quotes) population.

## -- Fit models for each outcome, including SOFA interaction ------------------
mental_mods_sofa <- map(
  mental_outcome_vars,
  ~ orm(
    as.formula(paste(., mod_rhs_sofa, sep = " ~ ")),
    data = model_df,
    x = TRUE, y = TRUE
  ) %>%
    robcov(cluster = model_df$study_site)
)

## -- Get adj medians + bounds for each treatment group, outcome; combine ------
mental_medians_sofa <- map_dfr(
  mental_mods_sofa, calc_medians_em,
  df = pred_df_sofa, em_vals = vals_sofa, em_var = "sofa_mod_imp_rand"
) %>%
  mutate(
    outcome_string = case_when(
      outcome == "dcfd_int" ~ "DCFDs",
      outcome == "del_int_all" ~ "Delirium",
      outcome == "hyperdel_int_all" ~ "Hyperactive\nDelirium",
      outcome == "hypodel_int_all" ~ "Hypoactive\nDelirium",
      outcome == "coma_int_all" ~ "Coma",
      TRUE ~ "other"
    ),
    p_sep = ifelse(p_int < 0.001, "", "="),
    outcome_text =
      sprintf("%s\n\nP%s%s", outcome_string, p_sep, formatp_nejm(p_int)),
    outcome_text = fct_shift(factor(outcome_text)),
    em_text = paste("Mod. SOFA =", rndformat(sofa_mod_imp_rand, 0)),
    em_text = fct_reorder(em_text, sofa_mod_imp_rand),
    trt_short = factor(
      ifelse(trt == "Placebo", "Plac", gsub(1, 3, trt)),
      levels = c("Plac", "Hal", "Zip")
    ),
    trt = factor(trt, levels = c("Placebo", "Haloperidol", "Ziprasidone"))
  )

## Plot medians + CIs
mental_medplot_sofa <- mental_medians_plot_em(
  median_df = mental_medians_sofa, em_string = "modified SOFA"
)

## Create table
mental_table_sofa <- mental_medians_sofa %>%
  mutate(
    effect_ci = glue(
      "{rndformat(quantile)} ({rndformat(lb)}, {rndformat(ub)})"
    )
  ) %>%
  dplyr::select(outcome_string, trt, sofa_mod_imp_rand, effect_ci, p_int) %>%
  mutate(
    outcome_string = gsub("\n", " ", outcome_string),
    sofa_mod_imp_rand = rndformat(sofa_mod_imp_rand, 1),
    p_int = formatp_nejm(p_int)
  )

Visual Results

Tabular Results

Time-to-Event Outcomes

For models involving competing risks (all outcomes other than mortality), only the subdistribution hazard ratio for the outcome of interest is presented.

## -- Fit models for each outcome, including SOFA interaction ------------------
## Death: No competing risks
death_30_mod_sofa <- cph(
  as.formula(paste("surv_death_30 ~", mod_rhs_sofa)),
  data = model_df,
  x = TRUE, y = TRUE
) %>%
  robcov(cluster = model_df$study_site)

death_90_mod_sofa <- cph(
  as.formula(paste("surv_death_90 ~", mod_rhs_sofa)),
  data = model_df,
  x = TRUE, y = TRUE
) %>%
  robcov(cluster = model_df$study_site)

## -- Fit competing risks models using finegray() objects prev. created --------
cr_mods_sofa <- map(cr_outcome_fgs, fit_cr_em, rhs = mod_rhs_sofa)
tte_mods_sofa <- c(list(death_30_mod_sofa, death_90_mod_sofa), cr_mods_sofa)

## -- Create a data.frame with one HR, CI per SOFA * trt * model comb ----------
get_ratios_sofa <- function(mod, sofa_val, outcome_name){
  if(missing(outcome_name)){
    outcome_name <- as.character(mod$sformula)[2]
  }
  
  ## Extract p-value for interaction from mod
  p_int <-
    anova(mod)["sofa_mod_imp_rand * trt  (Factor+Higher Order Factors)", "P"]
  
  tmp <- summary(
    mod,
    trt = "Placebo", sofa_mod_imp_rand = sofa_val,
    est.all = FALSE, antilog = FALSE
  ) %>%
    as.data.frame() %>%
    mutate(variable = rownames(.)) %>%
    separate(variable, into = c("vname", "comp")) %>%
    filter(vname == "trt") %>%
    dplyr::select(4, 6, 7, 10) %>%
    set_names(c("effect", "lcl", "ucl", "comp.c")) %>%
    ## Add a row for placebo
    bind_rows(
      data.frame("effect" = 0, "lcl" = 0, "ucl" = 0, "comp.c" = "Placebo")
    ) %>%
    ## Put everything on HR scale
    mutate_at(vars(-comp.c), exp) %>%
    mutate(
      outcome = outcome_name,
      sofa_mod_imp_rand = sofa_val,
      ref.c = "Placebo",
      p_int = p_int
    )
  
  return(tmp)
}

## Create list of arguments
tte_args_prep_sofa <- cross2(.x = tte_mods_sofa, .y = vals_sofa)
tte_args_sofa <- list(
  "mod" = map(tte_args_prep_sofa, 1),
  "sofa_val" = map_dbl(tte_args_prep_sofa, 2),
  "outcome_name" = rep(
    c("death_30", "death_90", "icudis_90", "hospdis_90", "mvlib_30",
      "readm_90"),
    times = length(vals_sofa)
  )
)

tte_ratios_sofa <- pmap_df(.l = tte_args_sofa, .f = get_ratios_sofa) %>%
  mutate(
    outcome_string = case_when(
      outcome == "death_30" ~ "Death,\n30 Days",
      outcome == "death_90" ~ "Death,\n90 Days",
      outcome == "icudis_90" ~ "ICU\nDischarge,\n90 Days",
      outcome == "hospdis_90" ~ "Hospital\nDischarge,\n90 Days",
      outcome == "mvlib_30" ~ "Liberation\nfrom MV,\n30 Days",
      outcome == "readm_90" ~ "ICU\nReadmission,\n90 Days",
      TRUE ~ "other"
    ),
    outcome_order = case_when(
      outcome == "death_30" ~ 1,
      outcome == "death_90" ~ 2,
      outcome == "mvlib_30" ~ 3,
      outcome == "icudis_90" ~ 4,
      outcome == "readm_90" ~ 5,
      outcome == "hospdis_90" ~ 6,
      TRUE ~ 7
    ),
    p_sep = ifelse(p_int < 0.001, "", "="),
    outcome_text =
      sprintf("%s\n\nP%s%s", outcome_string, p_sep, formatp_nejm(p_int)),
    outcome_text = fct_reorder(factor(outcome_text), outcome_order),
    em_text = paste("Mod. SOFA =", rndformat(sofa_mod_imp_rand, 0)),
    em_text = fct_reorder(em_text, sofa_mod_imp_rand),
    comp.c_short = factor(
      ifelse(comp.c == "Placebo", "Plac", substr(comp.c, 1, 3)),
      levels = c("Plac", "Hal", "Zip")
    ),
    comp.c = factor(comp.c, levels = c("Placebo", "Haloperidol", "Ziprasidone"))
  )

tte_plot_sofa <- plot_trt_ratios_em(
  ratio_df = tte_ratios_sofa, em_string = "modified SOFA", ratio_type = "Hazard"
)

## Create table
tte_table_sofa <- tte_ratios_sofa %>%
  mutate(
    effect_ci = glue(
      "{rndformat(effect)} ({rndformat(lcl)}, {rndformat(ucl)})"
    )
  ) %>%
  ## Placebo rows are meaningless, needed only for plots
  filter(comp.c != "Placebo") %>%
  dplyr::select(outcome_string, comp.c, sofa_mod_imp_rand, effect_ci, p_int) %>%
  mutate(
    sofa_mod_imp_rand = rndformat(sofa_mod_imp_rand, 1),
    p_int = formatp_nejm(p_int)
  )

Visual Results

Tabular Results

Pre-Existing Cognitive Impairment

We measure cognitive impairment prior to ICU admission via the IQCODE, usually administered to the patient’s surrogate. IQCODE is included as a linear, continuous variable in both the main effect and interaction terms of each model. For purposes of interpretation, we present the relationships between treatment and outcome adjusted to the 10th, 25th, 50th, 75th, and 90th percentiles of IQCODE in our randomized cohort; however, due to the distribution of IQCODE (heavily concentrated at 3 ) and low rates of pre-existing cognitive impairment in our cohort, these percentiles may result in fewer than 5 unique values.

## -- Create model RHS ---------------------------------------------------------
## Reminder: IQCODE is forced to be *linear* due to its distribution
mod_rhs_iqcode <- map_chr(
  cont_covars, ~ sprintf("rcs(%s, %s)", ., rcsknots)
) %>%
  c(., setdiff(notcont_covars, c("iqcode_total_ph", "trt"))) %>%
  c(., "iqcode_total_ph * trt") %>%
  paste(collapse = " + ")

## -- Create dataset of values to use when calculating conditional medians -----
## Use same values (median/mode) for everything except treatment and IQCODE
## Applies to all mental status outcomes

## Specify IQCODE values
vals_iqcode <- quantile(
  model_df$iqcode_total_ph, probs = em_quants, na.rm = TRUE
) %>%
  unique()

## Get matrix of treatment indicators:
##  Could not get the contrasts argument of model.matrix() to give me placebo
##  as reference. Create by hand.
trt_matrix_iqcode <- bind_rows(
  ## Get treatment indicator values, repeat as needed given vals_iqcode
  rep(
    list(as.data.frame(contr.treatment(levels(model_df$trt), base = 1))),
    length(vals_iqcode)
  )
) %>%
  ## Sort to group all placebo, haloperidol, ziprasidone rows together
  arrange(Ziprasidone, Haloperidol)

## Replace IQCODE columns in pred_df_org with updated IQCODE values
pred_df_iqcode_prep <- pred_df_org %>%
  dplyr::select(-starts_with("iqcode_total_ph")) %>%
  bind_rows(rep(list(.), length(vals_iqcode) - 1)) %>%
  bind_cols(data.frame(iqcode_total_ph = vals_iqcode))

## Repeat those values for each treatment
pred_df_iqcode <-
  rep(list(pred_df_iqcode_prep), length(levels(model_df$trt))) %>%
  bind_rows() %>%
  ## Add treatment levels to dataset
  bind_cols(trt = rep(levels(model_df$trt), nrow(pred_df_iqcode_prep))) %>%
  
  ## Create a model.matrix object, then leave out the intercept
  ##   model.matrix() handles dummy variables for categoricals nicely
  model.matrix(
    as.formula(sprintf("~ %s", paste(names(.), collapse = " + "))),
    .
  ) %>%
  ## Could not get the contrasts argument to give me placebo as reference.
  ## Wrangle this thing by hand.
  as.data.frame() %>%
  ## Remove intercept, original treatment columns
  dplyr::select(-1, -starts_with("trt")) %>%
  ## Add my own treatment columns, created above
  bind_cols(trt_matrix_iqcode) %>%
  
  ## Create interaction values
  mutate(
    iqcode_halop = iqcode_total_ph * Haloperidol,
    iqcode_zipras = iqcode_total_ph * Ziprasidone
  )

Though we see some statistically significant heterogeneity of effect, the adjusted differences do not seem to be clinically meaningful. The possible exception is ICU readmission; patients with the worst pre-existing cognitive impairment who were randomized to haloperidol had the highest adjusted rate of ICU readmission. This is worthy of further investigation; we also, however, note our low rates of readmission generally, and the wide confidence interval surrounding this estimate.

Mental Status Outcomes

Medians are adjusted to the median/mode values of all covariates except IQCODE and treatment, so that each represents the expected median number of DCFDs (for example) for a patient in each treatment group who is otherwise part of a “typical” (many air quotes) population.

## -- Fit models for each outcome, including IQCODE interaction ----------------
mental_mods_iqcode <- map(
  mental_outcome_vars,
  ~ orm(
    as.formula(paste(., mod_rhs_iqcode, sep = " ~ ")),
    data = model_df,
    x = TRUE, y = TRUE
  ) %>%
    robcov(cluster = model_df$study_site)
)

## -- Get adj medians + bounds for each treatment group, outcome; combine ------
mental_medians_iqcode <- map_dfr(
  mental_mods_iqcode, calc_medians_em,
  df = pred_df_iqcode, em_vals = vals_iqcode, em_var = "iqcode_total_ph"
) %>%
  mutate(
    outcome_string = case_when(
      outcome == "dcfd_int" ~ "DCFDs",
      outcome == "del_int_all" ~ "Delirium",
      outcome == "hyperdel_int_all" ~ "Hyperactive\nDelirium",
      outcome == "hypodel_int_all" ~ "Hypoactive\nDelirium",
      outcome == "coma_int_all" ~ "Coma",
      TRUE ~ "other"
    ),
    p_sep = ifelse(p_int < 0.001, "", "="),
    outcome_text =
      sprintf("%s\n\nP%s%s", outcome_string, p_sep, formatp_nejm(p_int)),
    outcome_text = fct_shift(factor(outcome_text)),
    em_text = paste("IQCODE =", rndformat(iqcode_total_ph, 3)),
    em_text = fct_reorder(em_text, iqcode_total_ph),
    trt_short = factor(
      ifelse(trt == "Placebo", "Plac", substr(trt, 1, 3)),
      levels = c("Plac", "Hal", "Zip")
    ),
    trt = factor(trt, levels = c("Placebo", "Haloperidol", "Ziprasidone"))
  )

## Plot medians + CIs
mental_medplot_iqcode <- mental_medians_plot_em(
  median_df = mental_medians_iqcode, em_string = "IQCODE"
)

## Create table
mental_table_iqcode <- mental_medians_iqcode %>%
  mutate(
    effect_ci = glue(
      "{rndformat(quantile)} ({rndformat(lb)}, {rndformat(ub)})"
    )
  ) %>%
  dplyr::select(outcome_string, trt, iqcode_total_ph, effect_ci, p_int) %>%
  mutate(
    outcome_string = gsub("\n", " ", outcome_string),
    iqcode_total_ph = rndformat(iqcode_total_ph, 3),
    p_int = formatp_nejm(p_int)
  )

Visual Results

Tabular Results

Time-to-Event Outcomes

For models involving competing risks (all outcomes other than mortality), only the subdistribution hazard ratio for the outcome of interest is presented.

## -- Fit models for each outcome, including IQCODE interaction ----------------
## Death: No competing risks
death_30_mod_iqcode <- cph(
  as.formula(paste("surv_death_30 ~", mod_rhs_iqcode)),
  data = model_df,
  x = TRUE, y = TRUE
) %>%
  robcov(cluster = model_df$study_site)

death_90_mod_iqcode <- cph(
  as.formula(paste("surv_death_90 ~", mod_rhs_iqcode)),
  data = model_df,
  x = TRUE, y = TRUE
) %>%
  robcov(cluster = model_df$study_site)

## -- Fit competing risks models using finegray() objects prev. created --------
cr_mods_iqcode <- map(cr_outcome_fgs, fit_cr_em, rhs = mod_rhs_iqcode)
tte_mods_iqcode <-
  c(list(death_30_mod_iqcode, death_90_mod_iqcode), cr_mods_iqcode)

## -- Create a data.frame with one HR, CI per SOFA * trt * model comb ----------
get_ratios_iqcode <- function(mod, iqcode_val, outcome_name){
  if(missing(outcome_name)){
    outcome_name <- as.character(mod$sformula)[2]
  }
  
  ## Extract p-value for interaction from mod
  p_int <-
    anova(mod)["iqcode_total_ph * trt  (Factor+Higher Order Factors)", "P"]
  
  tmp <- summary(
    mod,
    trt = "Placebo", iqcode_total_ph = iqcode_val,
    est.all = FALSE, antilog = FALSE
  ) %>%
    as.data.frame() %>%
    mutate(variable = rownames(.)) %>%
    separate(variable, into = c("vname", "comp")) %>%
    filter(vname == "trt") %>%
    dplyr::select(4, 6, 7, 10) %>%
    set_names(c("effect", "lcl", "ucl", "comp.c")) %>%
    ## Add a row for placebo
    bind_rows(
      data.frame("effect" = 0, "lcl" = 0, "ucl" = 0, "comp.c" = "Placebo")
    ) %>%
    ## Put everything on HR scale
    mutate_at(vars(-comp.c), exp) %>%
    mutate(
      outcome = outcome_name,
      iqcode_total_ph = iqcode_val,
      ref.c = "Placebo",
      p_int = p_int
    )
  
  return(tmp)
}

## Create list of arguments
tte_args_prep_iqcode <- cross2(.x = tte_mods_iqcode, .y = vals_iqcode)
tte_args_iqcode <- list(
  "mod" = map(tte_args_prep_iqcode, 1),
  "iqcode_val" = map_dbl(tte_args_prep_iqcode, 2),
  "outcome_name" = rep(
    c("death_30", "death_90", "icudis_90", "hospdis_90", "mvlib_30",
      "readm_90"),
    times = length(vals_iqcode)
  )
)

tte_ratios_iqcode <- pmap_df(.l = tte_args_iqcode, .f = get_ratios_iqcode) %>%
  mutate(
    outcome_string = case_when(
      outcome == "death_30" ~ "Death,\n30 Days",
      outcome == "death_90" ~ "Death,\n90 Days",
      outcome == "icudis_90" ~ "ICU\nDischarge,\n90 Days",
      outcome == "hospdis_90" ~ "Hospital\nDischarge,\n90 Days",
      outcome == "mvlib_30" ~ "Liberation\nfrom MV,\n30 Days",
      outcome == "readm_90" ~ "ICU\nReadmission,\n90 Days",
      TRUE ~ "other"
    ),
    outcome_order = case_when(
      outcome == "death_30" ~ 1,
      outcome == "death_90" ~ 2,
      outcome == "mvlib_30" ~ 3,
      outcome == "icudis_90" ~ 4,
      outcome == "readm_90" ~ 5,
      outcome == "hospdis_90" ~ 6,
      TRUE ~ 7
    ),
    p_sep = ifelse(p_int < 0.001, "", "="),
    outcome_text =
      sprintf("%s\n\nP%s%s", outcome_string, p_sep, formatp_nejm(p_int)),
    outcome_text = fct_reorder(factor(outcome_text), outcome_order),
    em_text = paste("IQCODE =", rndformat(iqcode_total_ph, 3)),
    em_text = fct_reorder(em_text, iqcode_total_ph),
    comp.c_short = factor(
      ifelse(comp.c == "Placebo", "Plac", substr(comp.c, 1, 3)),
      levels = c("Plac", "Hal", "Zip")
    ),
    comp.c = factor(comp.c, levels = c("Placebo", "Haloperidol", "Ziprasidone"))
  )

tte_plot_iqcode <- plot_trt_ratios_em(
  ratio_df = tte_ratios_iqcode, em_string = "IQCODE", ratio_type = "Hazard"
)

## Create table
tte_table_iqcode <- tte_ratios_iqcode %>%
  mutate(
    effect_ci = glue(
      "{rndformat(effect)} ({rndformat(lcl)}, {rndformat(ucl)})"
    )
  ) %>%
  ## Placebo rows are meaningless, needed only for plots
  filter(comp.c != "Placebo") %>%
  dplyr::select(outcome_string, comp.c, iqcode_total_ph, effect_ci, p_int) %>%
  mutate(
    iqcode_total_ph = rndformat(iqcode_total_ph, 3),
    p_int = formatp_nejm(p_int)
  )

Visual Results

Tabular Results

Medical vs Surgical ICU

“Surgical ICU patients” include patients who meet at least one of the following criteria:

  • Have a recorded primary ICU admission reason involving “surgery”
  • Had emergency or elective surgery between hospital admission and ICU admission
  • Went to the OR between ICU admission and study enrollment

Patients meeting none of the above criteria are considered to be medical ICU patients.

ICU type is included as a dichotomous variable, as both a main effect (not included in our primary analyses) and interacting with treatment. All main effects included in the primary adjusted models are also included in these exploratory models.

## -- Create model RHS ---------------------------------------------------------
mod_rhs_medsurg <- map_chr(
  cont_covars, ~ sprintf("rcs(%s, %s)", ., rcsknots)
) %>%
  c(., setdiff(notcont_covars, "trt")) %>%
  c(., "med_surg * trt") %>%
  paste(collapse = " + ")

## -- Create dataset of values to use when calculating conditional medians -----
## Use same values (median/mode) for everything except treatment and IQCODE
## Applies to all mental status outcomes

## Specify ICU type values: 0 = medical, 1 = surgical
vals_medsurg <- 0:1

## Get matrix of treatment indicators:
##  Could not get the contrasts argument of model.matrix() to give me placebo
##  as reference. Create by hand.
trt_matrix_medsurg <- bind_rows(
  ## Get treatment indicator values, repeat as needed given vals_iqcode
  rep(
    list(as.data.frame(contr.treatment(levels(model_df$trt), base = 1))),
    length(vals_medsurg)
  )
) %>%
  ## Sort to group all placebo, haloperidol, ziprasidone rows together
  arrange(Ziprasidone, Haloperidol)

## Replace ICU type columns in pred_df_org with updated IQCODE values
pred_df_medsurg_prep <- pred_df_org %>%
  bind_rows(rep(list(.), length(vals_medsurg) - 1)) %>%
  bind_cols(data.frame(med_surg = vals_medsurg))

## Repeat those values for each treatment
pred_df_medsurg <-
  rep(list(pred_df_medsurg_prep), length(levels(model_df$trt))) %>%
  bind_rows() %>%
  ## Add treatment levels to dataset
  bind_cols(trt = rep(levels(model_df$trt), nrow(pred_df_medsurg_prep))) %>%
  
  ## Create a model.matrix object, then leave out the intercept
  ##   model.matrix() handles dummy variables for categoricals nicely
  model.matrix(
    as.formula(sprintf("~ %s", paste(names(.), collapse = " + "))),
    .
  ) %>%
  ## Could not get the contrasts argument to give me placebo as reference.
  ## Wrangle this thing by hand.
  as.data.frame() %>%
  ## Remove intercept, original treatment columns
  dplyr::select(-1, -starts_with("trt")) %>%
  ## Add my own treatment columns, created above
  bind_cols(trt_matrix_medsurg) %>%
  
  ## Create interaction values
  mutate(
    medsurg_halop = med_surg * Haloperidol,
    medsurg_zipras = med_surg * Ziprasidone
  )

Aside from coma duration (where any effect modification is clinically minimal) and potentially liberation from mechanical ventilation, where ziprasidone may have some benefit among surgical patients, we see no effect modification from ICU type and the association between treatment and any of our primary or secondary outcomes.

Mental Status Outcomes

Medians are adjusted to the median/mode values of all covariates except ICU type and treatment, so that each represents the expected median number of DCFDs (for example) for a patient in each treatment group who is otherwise part of a “typical” (many air quotes) population.

## -- Fit models for each outcome, including ICU type interaction --------------
mental_mods_medsurg <- map(
  mental_outcome_vars,
  ~ orm(
    as.formula(paste(., mod_rhs_medsurg, sep = " ~ ")),
    data = model_df,
    x = TRUE, y = TRUE
  ) %>%
    robcov(cluster = model_df$study_site)
)

## -- Get adj medians + bounds for each treatment group, outcome; combine ------
mental_medians_medsurg <- map_dfr(
  mental_mods_medsurg, calc_medians_em,
  df = pred_df_medsurg, em_vals = vals_medsurg, em_var = "med_surg"
) %>%
  mutate(
    outcome_string = case_when(
      outcome == "dcfd_int" ~ "DCFDs",
      outcome == "del_int_all" ~ "Delirium",
      outcome == "hyperdel_int_all" ~ "Hyperactive\nDelirium",
      outcome == "hypodel_int_all" ~ "Hypoactive\nDelirium",
      outcome == "coma_int_all" ~ "Coma",
      TRUE ~ "other"
    ),
    p_sep = ifelse(p_int < 0.001, "", "="),
    outcome_text =
      sprintf("%s\n\nP%s%s", outcome_string, p_sep, formatp_nejm(p_int)),
    outcome_text = fct_shift(factor(outcome_text)),
    em_text = factor(med_surg, levels = 0:1, labels = c("Medical", "Surgical")),
    trt_short = factor(
      ifelse(trt == "Placebo", "Plac", substr(trt, 1, 3)),
      levels = c("Plac", "Hal", "Zip")
    ),
    trt = factor(trt, levels = c("Placebo", "Haloperidol", "Ziprasidone"))
  )

## Plot medians + CIs
mental_medplot_medsurg <- mental_medians_plot_em(
  median_df = mental_medians_medsurg, em_string = "ICU type"
)

## Create table
mental_table_medsurg <- mental_medians_medsurg %>%
  mutate(
    effect_ci = glue(
      "{rndformat(quantile)} ({rndformat(lb)}, {rndformat(ub)})"
    )
  ) %>%
  dplyr::select(outcome_string, trt, med_surg, effect_ci, p_int) %>%
  mutate(
    outcome_string = gsub("\n", " ", outcome_string),
    med_surg =
      factor(med_surg, levels = 0:1, labels = c("Medical", "Surgical")),
    p_int = formatp_nejm(p_int)
  )

Visual Results

Tabular Results

Time-to-Event Outcomes

For models involving competing risks (all outcomes other than mortality), only the subdistribution hazard ratio for the outcome of interest is presented.

## -- Fit models for each outcome, including ICU type interaction --------------
## Death: No competing risks
death_30_mod_medsurg <- cph(
  as.formula(paste("surv_death_30 ~", mod_rhs_medsurg)),
  data = model_df,
  x = TRUE, y = TRUE
) %>%
  robcov(cluster = model_df$study_site)

death_90_mod_medsurg <- cph(
  as.formula(paste("surv_death_90 ~", mod_rhs_medsurg)),
  data = model_df,
  x = TRUE, y = TRUE
) %>%
  robcov(cluster = model_df$study_site)

## -- Fit competing risks models using finegray() objects prev. created --------
cr_mods_medsurg <- map(cr_outcome_fgs, fit_cr_em, rhs = mod_rhs_medsurg)
tte_mods_medsurg <-
  c(list(death_30_mod_medsurg, death_90_mod_medsurg), cr_mods_medsurg)

## -- Create a data.frame with one HR, CI per type * trt * model comb ----------
get_ratios_medsurg <- function(mod, medsurg_val, outcome_name){
  if(missing(outcome_name)){
    outcome_name <- as.character(mod$sformula)[2]
  }

  ## Extract p-value for interaction from mod
  p_int <- anova(mod)["med_surg * trt  (Factor+Higher Order Factors)", "P"]

  tmp <- summary(
    mod,
    trt = "Placebo", med_surg = medsurg_val,
    est.all = FALSE, antilog = FALSE
  ) %>%
    as.data.frame() %>%
    mutate(variable = rownames(.)) %>%
    separate(variable, into = c("vname", "comp")) %>%
    filter(vname == "trt") %>%
    dplyr::select(4, 6, 7, 10) %>%
    set_names(c("effect", "lcl", "ucl", "comp.c")) %>%
    ## Add a row for placebo
    bind_rows(
      data.frame("effect" = 0, "lcl" = 0, "ucl" = 0, "comp.c" = "Placebo")
    ) %>%
    ## Put everything on HR scale
    mutate_at(vars(-comp.c), exp) %>%
    mutate(
      outcome = outcome_name,
      med_surg = medsurg_val,
      ref.c = "Placebo",
      p_int = p_int
    )

  return(tmp)
}

## Create list of arguments
tte_args_prep_medsurg <-
  cross2(.x = tte_mods_medsurg, .y = c("Medical", "Surgical"))
tte_args_medsurg <- list(
  "mod" = map(tte_args_prep_medsurg, 1),
  "medsurg_val" = map_chr(tte_args_prep_medsurg, 2),
  "outcome_name" = rep(
    c("death_30", "death_90", "icudis_90", "hospdis_90", "mvlib_30",
      "readm_90"),
    times = length(vals_medsurg)
  )
)

tte_ratios_medsurg <-
  pmap_df(.l = tte_args_medsurg, .f = get_ratios_medsurg) %>%
  mutate(
    outcome_string = case_when(
      outcome == "death_30" ~ "Death,\n30 Days",
      outcome == "death_90" ~ "Death,\n90 Days",
      outcome == "icudis_90" ~ "ICU\nDischarge,\n90 Days",
      outcome == "hospdis_90" ~ "Hospital\nDischarge,\n90 Days",
      outcome == "mvlib_30" ~ "Liberation\nfrom MV,\n30 Days",
      outcome == "readm_90" ~ "ICU\nReadmission,\n90 Days",
      TRUE ~ "other"
    ),
    outcome_order = case_when(
      outcome == "death_30" ~ 1,
      outcome == "death_90" ~ 2,
      outcome == "mvlib_30" ~ 3,
      outcome == "icudis_90" ~ 4,
      outcome == "readm_90" ~ 5,
      outcome == "hospdis_90" ~ 6,
      TRUE ~ 7
    ),
    p_sep = ifelse(p_int < 0.001, "", "="),
    outcome_text =
      sprintf("%s\n\nP%s%s", outcome_string, p_sep, formatp_nejm(p_int)),
    outcome_text = fct_reorder(factor(outcome_text), outcome_order),
    em_text = factor(med_surg, levels = c("Medical", "Surgical")),
    # em_text = fct_reorder(em_text, iqcode_total_ph),
    comp.c_short = factor(
      ifelse(comp.c == "Placebo", "Plac", substr(comp.c, 1, 3)),
      levels = c("Plac", "Hal", "Zip")
    ),
    comp.c = factor(comp.c, levels = c("Placebo", "Haloperidol", "Ziprasidone"))
  )

tte_plot_medsurg <- plot_trt_ratios_em(
  ratio_df = tte_ratios_medsurg, em_string = "ICU type", ratio_type = "Hazard"
)

## Create table
tte_table_medsurg <- tte_ratios_medsurg %>%
  mutate(
    effect_ci = glue(
      "{rndformat(effect)} ({rndformat(lcl)}, {rndformat(ucl)})"
    )
  ) %>%
  ## Placebo rows are meaningless, needed only for plots
  filter(comp.c != "Placebo") %>%
  dplyr::select(outcome_string, comp.c, med_surg, effect_ci, p_int) %>%
  mutate(
    p_int = formatp_nejm(p_int)
  )

Visual Results

Tabular Results

Sepsis/Septic Shock at ICU Admission

This section examines potential effect modification of the association between treatment and outcomes by whether patients had a recorded primary reason for ICU admission of sepsis/septic shock. Sepsis at admission is included as a dichotomous variable, as both a main effect (not included in our primary analyses) and interacting with treatment. All main effects included in the primary adjusted models are also included in these exploratory models.

## -- Create model RHS ---------------------------------------------------------
mod_rhs_sepsis <- map_chr(
  cont_covars, ~ sprintf("rcs(%s, %s)", ., rcsknots)
) %>%
  c(., setdiff(notcont_covars, "trt")) %>%
  c(., "sepsis_adm * trt") %>%
  paste(collapse = " + ")

## -- Create dataset of values to use when calculating conditional medians -----
## Use same values (median/mode) for everything except treatment and sepsis
## Applies to all mental status outcomes

## Specify sepsis values: 0 = medical, 1 = surgical
vals_sepsis <- 0:1

## Get matrix of treatment indicators:
##  Could not get the contrasts argument of model.matrix() to give me placebo
##  as reference. Create by hand.
trt_matrix_sepsis <- bind_rows(
  ## Get treatment indicator values, repeat as needed given vals_iqcode
  rep(
    list(as.data.frame(contr.treatment(levels(model_df$trt), base = 1))),
    length(vals_sepsis)
  )
) %>%
  ## Sort to group all placebo, haloperidol, ziprasidone rows together
  arrange(Ziprasidone, Haloperidol)

## Replace sepsis columns in pred_df_org with updated sepsis values
pred_df_sepsis_prep <- pred_df_org %>%
  bind_rows(rep(list(.), length(vals_sepsis) - 1)) %>%
  bind_cols(data.frame(sepsis_adm = vals_sepsis))

## Repeat those values for each treatment
pred_df_sepsis <-
  rep(list(pred_df_sepsis_prep), length(levels(model_df$trt))) %>%
  bind_rows() %>%
  ## Add treatment levels to dataset
  bind_cols(trt = rep(levels(model_df$trt), nrow(pred_df_sepsis_prep))) %>%
  
  ## Create a model.matrix object, then leave out the intercept
  ##   model.matrix() handles dummy variables for categoricals nicely
  model.matrix(
    as.formula(sprintf("~ %s", paste(names(.), collapse = " + "))),
    .
  ) %>%
  ## Could not get the contrasts argument to give me placebo as reference.
  ## Wrangle this thing by hand.
  as.data.frame() %>%
  ## Remove intercept, original treatment columns
  dplyr::select(-1, -starts_with("trt")) %>%
  ## Add my own treatment columns, created above
  bind_cols(trt_matrix_sepsis) %>%
  
  ## Create interaction values
  mutate(
    sepsis_halop = sepsis_adm * Haloperidol,
    sepsis_zipras = sepsis_adm * Ziprasidone
  )

Among patients septic/in septic shock at ICU readmission, ziprasidone treatment is associated with a small increase in coma duration, and both antipsychotics (but particularly haloperidol) are associated with a small decrease in time to ICU discharge compared to placebo.

Mental Status Outcomes

Medians are adjusted to the median/mode values of all covariates except sepsis and treatment, so that each represents the expected median number of DCFDs (for example) for a patient in each treatment group who is otherwise part of a “typical” (many air quotes) population.

## -- Fit models for each outcome, including sepsis interaction ----------------
mental_mods_sepsis <- map(
  mental_outcome_vars,
  ~ orm(
    as.formula(paste(., mod_rhs_sepsis, sep = " ~ ")),
    data = model_df,
    x = TRUE, y = TRUE
  ) %>%
    robcov(cluster = model_df$study_site)
)

## -- Get adj medians + bounds for each treatment group, outcome; combine ------
mental_medians_sepsis <- map_dfr(
  mental_mods_sepsis, calc_medians_em,
  df = pred_df_sepsis, em_vals = vals_sepsis, em_var = "sepsis_adm"
) %>%
  mutate(
    outcome_string = case_when(
      outcome == "dcfd_int" ~ "DCFDs",
      outcome == "del_int_all" ~ "Delirium",
      outcome == "hyperdel_int_all" ~ "Hyperactive\nDelirium",
      outcome == "hypodel_int_all" ~ "Hypoactive\nDelirium",
      outcome == "coma_int_all" ~ "Coma",
      TRUE ~ "other"
    ),
    p_sep = ifelse(p_int < 0.001, "", "="),
    outcome_text =
      sprintf("%s\n\nP%s%s", outcome_string, p_sep, formatp_nejm(p_int)),
    outcome_text = fct_shift(factor(outcome_text)),
    em_text = factor(
      sepsis_adm, levels = 0:1, labels = c("Non-Septic", "Septic/Shock")
    ),
    trt_short = factor(
      ifelse(trt == "Placebo", "Plac", substr(trt, 1, 3)),
      levels = c("Plac", "Hal", "Zip")
    ),
    trt = factor(trt, levels = c("Placebo", "Haloperidol", "Ziprasidone"))
  )

## Plot medians + CIs
mental_medplot_sepsis <- mental_medians_plot_em(
  median_df = mental_medians_sepsis, em_string = "sepsis at ICU admission"
)

## Create table
mental_table_sepsis <- mental_medians_sepsis %>%
  mutate(
    effect_ci = glue(
      "{rndformat(quantile)} ({rndformat(lb)}, {rndformat(ub)})"
    )
  ) %>%
  dplyr::select(outcome_string, trt, sepsis_adm, effect_ci, p_int) %>%
  mutate(
    outcome_string = gsub("\n", " ", outcome_string),
    sepsis_adm =
      factor(sepsis_adm, levels = 0:1, labels = c("Medical", "Surgical")),
    p_int = formatp_nejm(p_int)
  )

Visual Results

Tabular Results

Time-to-Event Outcomes

For models involving competing risks (all outcomes other than mortality), only the subdistribution hazard ratio for the outcome of interest is presented.

## -- Fit models for each outcome, including sepsis interaction ----------------
## Death: No competing risks
death_30_mod_sepsis <- cph(
  as.formula(paste("surv_death_30 ~", mod_rhs_sepsis)),
  data = model_df,
  x = TRUE, y = TRUE
) %>%
  robcov(cluster = model_df$study_site)

death_90_mod_sepsis <- cph(
  as.formula(paste("surv_death_90 ~", mod_rhs_sepsis)),
  data = model_df,
  x = TRUE, y = TRUE
) %>%
  robcov(cluster = model_df$study_site)

## -- Fit competing risks models using finegray() objects prev. created --------
cr_mods_sepsis <- map(cr_outcome_fgs, fit_cr_em, rhs = mod_rhs_sepsis)
tte_mods_sepsis <-
  c(list(death_30_mod_sepsis, death_90_mod_sepsis), cr_mods_sepsis)

## -- Create a data.frame with one HR, CI per type * trt * model comb ----------
get_ratios_sepsis <- function(mod, sepsis_val, outcome_name){
  if(missing(outcome_name)){
    outcome_name <- as.character(mod$sformula)[2]
  }

  ## Extract p-value for interaction from mod
  p_int <- anova(mod)["sepsis_adm * trt  (Factor+Higher Order Factors)", "P"]

  tmp <- summary(
    mod,
    trt = "Placebo", sepsis_adm = sepsis_val,
    est.all = FALSE, antilog = FALSE
  ) %>%
    as.data.frame() %>%
    mutate(variable = rownames(.)) %>%
    separate(variable, into = c("vname", "comp")) %>%
    filter(vname == "trt") %>%
    dplyr::select(4, 6, 7, 10) %>%
    set_names(c("effect", "lcl", "ucl", "comp.c")) %>%
    ## Add a row for placebo
    bind_rows(
      data.frame("effect" = 0, "lcl" = 0, "ucl" = 0, "comp.c" = "Placebo")
    ) %>%
    ## Put everything on HR scale
    mutate_at(vars(-comp.c), exp) %>%
    mutate(
      outcome = outcome_name,
      sepsis_adm = sepsis_val,
      ref.c = "Placebo",
      p_int = p_int
    )

  return(tmp)
}

## Create list of arguments
tte_args_prep_sepsis <-
  cross2(.x = tte_mods_sepsis, .y = c("Non-septic", "Sepsis/septic shock"))
tte_args_sepsis <- list(
  "mod" = map(tte_args_prep_sepsis, 1),
  "sepsis_val" = map_chr(tte_args_prep_sepsis, 2),
  "outcome_name" = rep(
    c("death_30", "death_90", "icudis_90", "hospdis_90", "mvlib_30",
      "readm_90"),
    times = length(vals_sepsis)
  )
)

tte_ratios_sepsis <-
  pmap_df(.l = tte_args_sepsis, .f = get_ratios_sepsis) %>%
  mutate(
    outcome_string = case_when(
      outcome == "death_30" ~ "Death,\n30 Days",
      outcome == "death_90" ~ "Death,\n90 Days",
      outcome == "icudis_90" ~ "ICU\nDischarge,\n90 Days",
      outcome == "hospdis_90" ~ "Hospital\nDischarge,\n90 Days",
      outcome == "mvlib_30" ~ "Liberation\nfrom MV,\n30 Days",
      outcome == "readm_90" ~ "ICU\nReadmission,\n90 Days",
      TRUE ~ "other"
    ),
    outcome_order = case_when(
      outcome == "death_30" ~ 1,
      outcome == "death_90" ~ 2,
      outcome == "mvlib_30" ~ 3,
      outcome == "icudis_90" ~ 4,
      outcome == "readm_90" ~ 5,
      outcome == "hospdis_90" ~ 6,
      TRUE ~ 7
    ),
    p_sep = ifelse(p_int < 0.001, "", "="),
    outcome_text =
      sprintf("%s\n\nP%s%s", outcome_string, p_sep, formatp_nejm(p_int)),
    outcome_text = fct_reorder(factor(outcome_text), outcome_order),
    em_text = factor(
      sepsis_adm, levels = c("Non-septic", "Sepsis/septic shock")
    ),
    # em_text = fct_reorder(em_text, iqcode_total_ph),
    comp.c_short = factor(
      ifelse(comp.c == "Placebo", "Plac", substr(comp.c, 1, 3)),
      levels = c("Plac", "Hal", "Zip")
    ),
    comp.c = factor(comp.c, levels = c("Placebo", "Haloperidol", "Ziprasidone"))
  )

tte_plot_sepsis <- plot_trt_ratios_em(
  ratio_df = tte_ratios_sepsis,
  em_string = "sepsis at ICU admission",
  ratio_type = "Hazard"
)

## Create table
tte_table_sepsis <- tte_ratios_sepsis %>%
  mutate(
    effect_ci = glue(
      "{rndformat(effect)} ({rndformat(lcl)}, {rndformat(ucl)})"
    )
  ) %>%
  ## Placebo rows are meaningless, needed only for plots
  filter(comp.c != "Placebo") %>%
  dplyr::select(outcome_string, comp.c, sepsis_adm, effect_ci, p_int) %>%
  mutate(
    p_int = formatp_nejm(p_int)
  )

Visual Results

Tabular Results

Code for Creation of Publication Figures

These figures combine results included in separate sections earlier in this document. The goal is to create high-resolution graphics for both manuscript publication and future presentations.

Listing of planned figures in primary manuscript:

  1. CONSORT information (done by clinical authors; information provided in Screening, Consent, and Randomization)
  2. Survival: 90-day KM curve
  3. Mental status outcomes: medians, DCFDs, delirium, coma duration

Possible figures for supplement:

  1. Cumulative incidence curves: ICU discharge, hospital discharge, MV liberation, ICU readmission (outcomes of interest only)
  2. Medians, hypoactive/hyperactive delirium
  3. Adjusted hazard ratios for all TTE outcomes
  4. Complete cumulative incidence curves for all TTE outcomes, including curves for death/discharge and N at risk
  5. Effect modification figures

Mental Status Outcomes, Primary Analysis

Suggested caption:

During the 14-day treatment period, the primary outcome (delirium/coma-free days) and secondary outcomes (durations of delirium and coma) were similar in the three treatment groups. P-values are computed for the entire association between treatment and the outcome. Medians and p-values are calculated using proportional odds logistic regression clustered by study site, and are adjusted for age at study consent; preexisting cognitive impairment (IQCODE), frailty (CSHA Clinical Frailty Score), and comorbidities (Charlson Comorbidities Index); and severity of illness (modified SOFA) and level of arousal (RASS) at randomization.

(Similar for appendix, hyperactive/hypoactive delirium.)

## Helpful links for using Lato:
## Using a non-default font by Zev Ross
## https://www.zevross.com/blog/2014/07/30/tired-of-using-helvetica-in-your-r-graphics-heres-how-to-use-the-fonts-you-like-2/
## Why didn't my spaces show up?
## https://stackoverflow.com/questions/27542302/ggplot-embedded-fonts-in-pdf
## Doing the same with png by Andrew Heiss
## https://www.andrewheiss.com/blog/2017/09/27/working-with-r-cairo-graphics-custom-fonts-and-ggplot/

## DCFDs, delirium, coma all in one figure -------------------------------------
## Row 1: DCFDs; Row 2: Delirium + Coma
## Facet all for consistency

## Prep function: Create text string with title, p-value for treatment
##  (if requested) given a model + title
make_outcome_string <- function(mod_obj, title_string, use_p = FALSE){
  if(use_p){
    p_trt <- anova(mod_obj)["trt", "P"]
    sprintf(
      "%s; P%s%s",
      title_string, ifelse(p_trt < 0.001, '', '='), formatp_nejm(p_trt)
    )
  } else{
    sprintf("%s", title_string)
  }
}

## -- Function to create separate plots for each mental outcome/set ------------
plot_medians_pub <- function(
  med_df,               ## Needs columns: trt; quantile; lb; ub; title_text
  facet_outcome = TRUE, ## Use facets? If not, info gets put in title
  ftext_size = 1.3,     ## multiplier * basetext_size for facet titles
  trt_abb       = TRUE, ## Use abbreviated treatment names?
  use_xtitle    = TRUE  ## Include X axis title?
){
  ## Make sure treatment is in correct order
  med_df <- med_df %>%
    mutate(
      trt = factor(trt, levels = c("Placebo", "Haloperidol", "Ziprasidone")),
      trt_short = forcats::fct_relabel(
        trt, ~ ifelse(. == "Placebo", "Plac", substr(., 1, 3))
      )
    )

  ## Set aes() according to whether we want full or abbreviated treatment names
  if(trt_abb){
    p <- ggplot(data = med_df, aes(x = trt_short, y = quantile))
  } else{
    p <- ggplot(data = med_df, aes(x = trt, y = quantile))
  }
  
  ## Bulk of plot
  p <- p +
    geom_pointrange(
      aes(ymin = lb, ymax = ub),
      color = as.character(palette_colors[["dred"]]), size = 0.8#, shape = 1
    ) +
    scale_y_continuous(
      limits = c(0, 14),
      breaks = seq(0, 14, 2),
      name = "Adjusted Median Days (95% Confidence Interval)"
    ) +
    coord_flip() +
    theme(
      axis.title.y = element_blank(),
      axis.ticks.y = element_blank(),
      axis.text.y = element_text(face = "bold", size = basetext_size)
    )

  ## Include outcome/testing info in either facet titles or plot title
  if(facet_outcome){
    p <- p +
      facet_wrap(~ title_text, nrow = 1) +
      theme(
        strip.text.x =
          element_text(hjust = 0, size = basetext_size * ftext_size),
        strip.background = element_blank()
      )
  } else{
    p <- p + labs(title = unique(med_df$title_text))
  }
  
  ## Remove or format X axis title
  if(!use_xtitle){
    p <- p + theme(axis.title.x = element_blank())
  } else{
    p <- p + theme(axis.title.x = element_text(vjust = 0))
  }

  return(p)
}

## -- Create one plot for DCFDs, one for delirium + coma -----------------------
medians_dcfd_pub <- plot_medians_pub(
  med_df = dcfd_adjmeds %>%
    mutate(
      title_text = make_outcome_string(dcfd_mod, "A: Delirium/Coma-Free Days")
    ),
  trt_abb = FALSE,
  use_xtitle = FALSE
)

medians_delcoma_pub <- plot_medians_pub(
  med_df = bind_rows(
    del_adjmeds %>%
      mutate(title_text = make_outcome_string(del_mod, "B: Delirium Days")),
    coma_adjmeds %>%
      mutate(title_text = make_outcome_string(coma_mod, "C: Coma Days"))
  ),
  trt_abb = FALSE,
  use_xtitle = TRUE
)

medians_deltypes_pub <- plot_medians_pub(
  med_df = bind_rows(
    hyperdel_adjmeds %>%
      mutate(
        title_text = make_outcome_string(
          hyperdel_mod, "A: Hyperactive Delirium"
        )
      ),
    hypodel_adjmeds %>%
      mutate(
        title_text = make_outcome_string(hypodel_mod, "B: Hypoactive Delirium")
      )
  ),
  ftext_size = 1.0,
  trt_abb = FALSE,
  use_xtitle = TRUE
) +
  scale_y_continuous(
    limits = c(0, 6), name = "Adjusted Median Days (95% Confidence Interval)"
  )

## Save plots as pdf, png
## A Heiss's cool %T>% trick he tweeted me doesn't work with multiplot(), sadly
ggsave(
  filename = "mindusa_mentaloutcomes.pdf",
  multiplot(
    medians_dcfd_pub, medians_delcoma_pub,
    layout = matrix(c(1, 2), byrow = TRUE, nrow = 2)
  ),
  path = "pubfigures/pdf",
  device = cairo_pdf, ## cairo_pdf() to embed fonts, keep spaces
  width = 8, height = 6.5, units = "in"
)

ggsave(
  filename = "mindusa_mentaloutcomes.png",
  multiplot(
    medians_dcfd_pub, medians_delcoma_pub,
    layout = matrix(c(1, 2), byrow = TRUE, nrow = 2)
  ),
  path = "pubfigures/png",
  type = "cairo", dpi = 400, width = 8, height = 6.5, units = "in"
)

medians_deltypes_pub %T>%
  ggsave(
    filename = "mindusa_delsubtypes.pdf",
    .,
    path = "pubfigures/pdf",
    device = cairo_pdf, ## cairo_pdf() to embed fonts, keep spaces
    width = 6, height = 4, units = "in"
  ) %T>%
  ggsave(
    filename = "mindusa_delsubtypes.png",
    .,
    path = "pubfigures/png",
    type = "cairo", dpi = 400, width = 6, height = 4, units = "in"
  )

90-Day Survival

## -- 1) Kaplan-Meier curve, death to 90 days ----------------------------------
## summary(survfit()) object at every 15 days
sf_death_90_pub <- summary(
  survfit(
    surv_death_90 ~ trt,
    data = model_df %>%
      mutate(
        trt = factor(trt, levels = c("Ziprasidone", "Haloperidol", "Placebo"))
      )
  ),
  times = seq(0, 90, 15)
)

## Publication version of KM curve without N at risk table
##  (will create that manually next)
km_death_90_pub <- km_plot_death(
  sf = sf_death_90, lr = logrank_death_90, inc_risktable = TRUE, time = 90
)

km_death_90_pub$plot <- km_death_90_pub$plot +
  labs(
    title = "Kaplan-Meier Curve, 90-Day All-Cause Death",
    ## Remove p-values at stat reviewer request :raised_hands:
    # subtitle = glue(
    #   "At 30 days, adjusted P={formatp_nejm(anova(death_30_mod)['trt', 'P'])};",
    #   " at 90 days, adjusted P={formatp_nejm(anova(death_90_mod)['trt', 'P'])}"
    # )
    ylab = " \n\n\n\n\n\nProbability of Overall Survival (%)"
  ) +
  theme(
    plot.subtitle = element_blank(),
    legend.position = c(0.015, 0.03),
    axis.title.y = element_text(vjust = -5),
    axis.text.x = element_blank(),
    axis.ticks.x = element_blank()
  )

## Not needed for current configuration, which keeps KM curve separate from CIFs
# ## 2) N at risk table ----------------------------------------------------------
# ## Need to do separately/manually - got spacing issues when trying to combine
# ## survminer version with CIF curves (probably some grid issue)
# nrisk_death_90_pub <- cr_risktable_plot(sf_death_90_pub, facet_trts = FALSE) +
#   scale_y_discrete(labels = c("Placebo", "Haloperidol", "Ziprasidone")) +
#   theme(plot.margin = unit(c(0, 5.5, 5.5, 5.5), "pt"))

km_death_90_pub$table <- km_death_90_pub$table +
   theme(axis.title.x = element_text(face = "bold"))

## Save KM + N at risk only
ggsave(
  filename = "mindusa_kmnrisk.pdf",
  multiplot(
    km_death_90_pub,
    layout = matrix(c(1, 1, 2), ncol = 1)
  ),
  path = "pubfigures/pdf",
  device = cairo_pdf, ## cairo_pdf() to embed fonts, keep spaces
  width = 7, height = 6.5, units = "in"
)
ggsave(
  filename = "mindusa_kmnrisk.png",
  multiplot(
    km_death_90_pub,
    layout = matrix(c(1, 1, 2), ncol = 1)
  ),
  path = "pubfigures/png",
  type = "cairo", dpi = 400, width = 7, height = 6.5, units = "in"
)

Cumulative Incidence Curves for Outcomes with Competing Risks

cif_data <- pmap_df(
  .l = list(
    cuminc_obj =
      list(icudis_90_cif, hospdis_90_cif, mvlib_30_cif, readm_90_cif),
    censor_time = c(90, 90, 30, 90),
    cph_mod = list(icudis_90_mod, hospdis_90_mod, mvlib_30_mod, readm_90_mod)
  ),
  .f = prep_cuminc_df
) %>%
  mutate(trt = factor(trt, levels = c("Ziprasidone", "Haloperidol", "Placebo")))

cif_pub_facet <- ggplot(
  data = cif_data %>% filter(is_subdist),
  aes(x = time, y = est, color = trt, fill = trt)
) +
  facet_wrap(~ tte_outcome_1l, scales = "free_x") +
  geom_ribbon(
    aes(ymin = lb, ymax = ub), colour = NA, alpha = 0.15
  ) +
  geom_step() +
  scale_color_manual(values = mindusa_trtcols_long) +
  scale_fill_manual(values = mindusa_trtcols_long) +
  scale_x_continuous(name = "Days after Randomization", breaks = cif_breaks) +
  scale_y_continuous(
    name = "Cumulative Incidence Probability",
    limits = c(0, 1),
    breaks = seq(0, 1, 0.25), labels = paste0(seq(0, 1, 0.25)*100, "%")
  ) +
  theme(
    strip.text = element_text(hjust = 0, size = basetext_size * 0.9),
    strip.background = element_blank(),
    axis.text = element_text(size = basetext_size * 0.7),
    ## When kept a separate plot
    legend.title = element_blank(),
    legend.position = c(0.89, 0.1),
    legend.background = element_blank(),
    legend.direction = "vertical",
    legend.text.align = 1
    # legend.position = "none" ## unnecessary when combined with KM plot
  )

## Save CIF curves alone
cif_pub_facet %T>%
  ggsave(
    filename = "mindusa_tteoutcomes.pdf", ., path = "pubfigures/pdf",
    device = cairo_pdf, ## cairo_pdf() to embed fonts, keep spaces
    width = 7, height = 6.5, units = "in"
  ) %T>%
  ggsave(
    filename = "mindusa_tteoutcomes.png", ., path = "pubfigures/png",
    type = "cairo", dpi = 400, width = 7, height = 6.5, units = "in"
  )

All TTE Outcomes Combined

Suggested caption:

The study population had 73% survival at 30 days and 65% survival at 90 days. In adjusted analyses, neither haloperidol (…) nor ziprasidone (…) affected 30-day survival compared with placebo (across groups, adjusted P = …). Ziprasidone had no effect on 90-day survival (HR…); haloperidol’s effect on 90-day survival trended toward harm in adjusted analyses (HR…). P-values for 30- and 90-day death refer to the entire association between treatment and mortality and are calculated using Cox proportional hazards models clustered by study site. Models are adjusted for age at study consent; preexisting cognitive impairment (IQCODE), frailty (CSHA Clinical Frailty Score), and comorbidities (Charlson Comorbidities Index); and severity of illness (modified SOFA) and level of arousal (RASS) at randomization.

There were no differences between treatment groups in time to liberation from mechanical ventilation, ICU discharge, or hospital discharge. In adjusted analyses there was a difference in ICU readmission across groups, with patients treated with ziprasidone having a slightly lower readmission rate among those who survived their initial ICU stay. P-values refer to the overall effect of treatment. They are calculated using the Fine-Gray method for competing risks (clustered by study site), and adjusted for age at study consent; preexisting cognitive impairment (IQCODE), frailty (CSHA Clinical Frailty Score), and comorbidities (Charlson Comorbidities Index); and severity of illness (modified SOFA) and level of arousal (RASS) at randomization.

CIF Details

Suggested caption:

[These figures] present the cumulative incidence probabilities for time-to-event outcomes, alongside those for competing risks of death and (where appropriate) ICU discharge prior to the event of interest. All four outcomes have a competing risk of death prior to the event; ICU readmission and liberation from mechanical ventilation also have a competing risk of ICU discharge prior to the event. P-values refer to the overall effect of treatment. They are calculated using the Fine-Gray method for competing risks (clustered by study site), and adjusted for age at study consent; preexisting cognitive impairment (IQCODE), frailty (CSHA Clinical Frailty Score), and comorbidities (Charlson Comorbidities Index); and severity of illness (modified SOFA) and level of arousal (RASS) at randomization.

## -- Wrapper function ---------------------------------------------------------
save_cif_suppplots <- function(
  cuminc_obj,
  sf_sum,
  main_event,
  event_string_cif,
  event_string_rt,
  cph_mod,
  xmax = 95, time_breaks = seq(0, 90, 15), text_size,
  file_prefix
){
  cif_supp <- create_cif_manual(
    cuminc_obj = cuminc_obj,
    main_event = main_event,
    event_string = event_string_cif,
    cph_mod = cph_mod
  ) +
    theme(
      legend.text = element_text(size = basetext_size * 0.6),
      legend.key.size = unit(0.45, "cm")
    )
  rt_supp <- cr_risktable_plot(
    sf_sum = sf_sum,
    main_event = main_event,
    event_string = event_string_rt,
    text_size = text_size
  )

  ggsave(
    filename = sprintf("mindusa_%s_cif.pdf", file_prefix),
    cr_combine_plots(
      cif = cif_supp,
      rt = rt_supp,
      xmax = xmax,
      time_breaks = time_breaks,
      caption_string = NULL
    ),
    path = "pubfigures/pdf",
    device = cairo_pdf,
    width = 8, height = 5.5, units = "in"
  )
  ggsave(
    filename = sprintf("mindusa_%s_cif.png", file_prefix),
    cr_combine_plots(
      cif = cif_supp,
      rt = rt_supp,
      xmax = xmax,
      time_breaks = time_breaks,
      caption_string = NULL
    ),
    path = "pubfigures/png",
    type = "cairo", dpi = 400, width = 8, height = 5.5, units = "in"
  )
}

pwalk(
  .l = list(
    cuminc_obj = list(
      icudis_90_cif, hospdis_90_cif, mvlib_30_cif, readm_90_cif
    ),
    sf_sum = list(
      icudis_90_sfsum, hospdis_90_sfsum, mvlib_30_sfsum, readm_90_sfsum
    ),
    main_event =
      c("ICU Discharge", "Hospital Discharge", "MV Liberation", "Readmission"),
    event_string_cif = c(
      "ICU discharge", "hospital discharge", "MV liberation", "readmission"
    ),
    event_string_rt = c(
      "of ICU discharges", "of hospital discharges", "liberated from MV",
      "readmitted"
    ),
    cph_mod = list(icudis_90_mod, hospdis_90_mod, mvlib_30_mod, readm_90_mod),
    xmax = c(95, 95, 32.5, 95),
    time_breaks = list(
      seq(0, 90, 15), seq(0, 90, 15), seq(0, 30, 5), seq(0, 90, 15)
    ),
    text_size = c(0.2, 0.2, 0.15, 0.125),
    file_prefix = c("icudis", "hospdis", "mvlib", "readm")
  ),
  .f = save_cif_suppplots
)

Adjusted Subdistribution Hazard Ratios, All Time-to-Event Outcomes

Suggested caption:

[This figure] presents adjusted hazard ratios for haloperidol and ziprasidone vs placebo for each time-to-event outcome. Hazard ratios are calculated using Cox proportional hazards regression (death) or Fine-Gray competing risks models (all other outcomes), with competing risks of death and, for MV liberation and ICU readmission, discharge prior to the primary event of interest. All are adjusted for age at study consent; preexisting cognitive impairment (IQCODE), frailty (CSHA Clinical Frailty Score), and comorbidities (Charlson Comorbidities Index); and severity of illness (modified SOFA) and level of arousal (RASS) at randomization.

Death and hospital and ICU discharge are analyzed among all 566 randomized patients. Liberation from mechanical ventilation is analyzed among the 527 randomized patients who received either type of mechanical ventilation at or within 24 hours after randomization. ICU readmission is analyzed only among the 497 randomized patients who survived their initial ICU stay and were discharged to the floor.

## -- Combine all HR data.frames -----------------------------------------------
all_hrs <- bind_rows(
  death_30_hrs, death_90_hrs,
  mvlib_30_hrs %>% mutate(outcome = "mvlib_30"),
  icudis_90_hrs %>% mutate(outcome = "icudis_90"),
  readm_90_hrs %>% mutate(outcome = "readm_90"),
  hospdis_90_hrs %>% mutate(outcome = "hospdis_90")
) %>%
  separate(
    outcome, into = c("junk", "endpt", "time"), sep = "_", fill = "left"
  ) %>%
  dplyr::select(-junk) %>%
  mutate(
    linecol = factor(
      ifelse(endpt == "death" & time == 90, 1, 2),
      levels = 1:2, labels = c("90 Days", "30 Days")
    ),
    facet_text = case_when(
      endpt == "death" ~ sprintf(
        "Death\n\n30 days: P=%s; 90 days: P=%s",
        formatp_nejm(anova(death_30_mod)['trt', 'P']),
        formatp_nejm(anova(death_90_mod)['trt', 'P'])
      ),
      endpt == "mvlib" ~ sprintf(
        "Liberation from MV\n\n30 days: P=%s",
        formatp_nejm(anova(mvlib_30_mod)['trt', 'P'])
      ),
      endpt == "icudis" ~ sprintf(
        "ICU Discharge\n\n90 days: P=%s",
        formatp_nejm(anova(icudis_90_mod)['trt', 'P'])
      ),
      endpt == "readm" ~ sprintf(
        "ICU Readmission\n\n90 days: P=%s",
        formatp_nejm(anova(readm_90_mod)['trt', 'P'])
      ),
      endpt == "hospdis" ~ sprintf(
        "Hospital Discharge\n\n90 days: P=%s",
        formatp_nejm(anova(hospdis_90_mod)['trt', 'P'])
      ),
      TRUE ~ "other"
    ),
    outcome_order = case_when(
      endpt == "mvlib" ~ 1,
      endpt == "icudis" ~ 2,
      endpt == "readm" ~ 3,
      endpt == "hospdis" ~ 4,
      TRUE ~ 5
    ),
    facet_text = fct_reorder(facet_text, outcome_order)
  )

## -- Create faceted plot ------------------------------------------------------
all_hrs_plot <- ggplot(data = all_hrs, aes(y = effect, x = comp.c)) +
  facet_wrap(~ facet_text) +
  ## Fake row to set up order properly
  geom_point(shape = NA) +
  ## Reference line at 1 (no effect)
  geom_hline(yintercept = 1, linetype = "solid",
             colour = palette_colors["lgray"], size = 2) +
  ## Plot a point for control group
  geom_point(
    shape = 15, colour = "black", size = 4,
    data = all_hrs %>% filter(is.ref)
  ) +
  ## Add ratios, CIs for treatment groups vs control
  geom_pointrange(
    aes(
      ymin = lcl, ymax = ucl,
      group = linecol, colour = linecol, shape = linecol, size = linecol
    ),
    position = position_dodge(width = 0.8),
    data = all_hrs %>% filter(!is.ref)
  ) +
  scale_colour_manual(
    values = c(
      "30 Days" = palette_colors[["dred"]],
      "90 Days" = palette_colors[["dgray"]]
    )
  ) +
  scale_shape_manual(values = c(15, 16)) +
  scale_size_manual(values = c(0.85, 1)) +
  scale_x_discrete(labels = c("Plac", "Hal", "Zip")) +
  scale_y_continuous(name = "Adjusted Hazard Ratio (95% Confidence Interval)") +
  labs(
    title = "Adjusted Hazard Ratios, Time-to-Event Outcomes",
    caption = glue(
      "\nAdjusted analysis using Cox proportional hazards regression (death) or Fine-Gray competing risks analysis.\nCompeting risks include death (all outcomes) and discharge (MV liberation, readmission) prior to the event of interest.\nFor outcomes with competing risks, hazard ratios are for the primary subdistribution specified."
    )
  ) +
  theme(
    legend.position = c(0.59, 0.07),
    legend.direction = "vertical",
    legend.title = element_blank(),
    legend.text = element_text(size = basetext_size * 0.8),
    legend.background = element_blank(),
    legend.key = element_blank(),
    legend.key.size = unit(0.4, "cm"),
    plot.caption = element_text(size = basetext_size * 0.7),
    axis.title.y = element_blank(),
    axis.ticks.y = element_blank(),
    axis.text.y = element_text(face = "bold", size = basetext_size)
  ) +
  coord_flip() +
  guides(
    colour = guide_legend(reverse = TRUE),
    shape = guide_legend(reverse = TRUE),
    size = guide_legend(reverse = TRUE)
  )

all_hrs_plot %T>%
  ggsave(
    filename = "mindusa_adjhrs.pdf",
    .,
    path = "pubfigures/pdf",
    device = cairo_pdf, ## cairo_pdf() to embed fonts, keep spaces
    width = 7, height = 6, units = "in"
  ) %T>%
  ggsave(
    filename = "mindusa_adjhrs.png",
    .,
    path = "pubfigures/png",
    type = "cairo", dpi = 400, width = 7, height = 6, units = "in"
  )

Effect Modification Figures

These figures are quite similar to those shown earlier (just with titles), so will not be reproduced here.

Adjusted Medians for Time-to-Event Outcomes

Suggested captions:

[These figures] present the relationship between treatment and mental status outcomes at various levels of [age, IQCODE, sepsis, ICU type, SOFA] among all 566 randomized patients. Medians and confidence limits are calculated using proportional odds logistic regression and adjusted for age at study consent; preexisting cognitive impairment (IQCODE), frailty (CSHA Clinical Frailty Score), and comorbidities (Charlson Comorbidities Index); and severity of illness (modified SOFA) and level of arousal (RASS) at randomization.

Hazard Ratios for Time-to-Event Outcomes

Suggested captions:

[These figures] present the adjusted hazard ratios for haloperidol and ziprasidone vs placebo for each time-to-event outcome at various levels of [age, IQCODE, sepsis, ICU type, SOFA]. Hazard ratios are calculated using Cox proportional hazards regression (death) or Fine-Gray competing risks models (all other outcomes), with competing risks of death and, for MV liberation and ICU readmission, discharge prior to the primary event of interest. All are adjusted for age at study consent; preexisting cognitive impairment (IQCODE), frailty (CSHA Clinical Frailty Score), and comorbidities (Charlson Comorbidities Index); and severity of illness (modified SOFA) and level of arousal (RASS) at randomization.

Death and hospital and ICU discharge are analyzed among all 566 randomized patients. Liberation from mechanical ventilation is analyzed among the 527 randomized patients who received either type of mechanical ventilation at or within 24 hours after randomization. ICU readmission is analyzed only among the 497 randomized patients who survived their initial ICU stay and were discharged to the floor.

## -- Wrappers to create pub versions (with title_string) and save -------------
## Mental outcomes
save_mental_em_pub <- function(
  median_df,
  em_string,
  title_text,
  file_text,
  file_ht
){
  em_pub <- mental_medians_plot_em(
    median_df = median_df,
    em_string = em_string,
    title_string = sprintf(
      "Treatment vs Mental Status Outcomes,\nModified by %s", title_text
    )
  )

  em_pub %T>%
    ggsave(
      filename = sprintf("mindusa_mentalby%s.pdf", file_text),
      .,
      path = "pubfigures/pdf",
      device = cairo_pdf, ## cairo_pdf() to embed fonts, keep spaces
      width = 7, height = file_ht, units = "in"
    ) %T>%
    ggsave(
      filename = sprintf("mindusa_mentalby%s.png", file_text),
      .,
      path = "pubfigures/png",
      type = "cairo", dpi = 400, width = 7, height = file_ht, units = "in"
    )
  
}

## Time-to-event
save_tte_em_pub <- function(
  ratio_df,
  em_string,
  title_text,
  file_text,
  file_ht
){
  em_pub <- plot_trt_ratios_em(
    ratio_df = ratio_df,
    em_string = em_string,
    title_string = sprintf(
      "Treatment vs Time-to-Event Outcomes,\nModified by %s", title_text
    ),
    ratio_type = "Hazard"
  )

  em_pub %T>%
    ggsave(
      filename = sprintf("mindusa_tteby%s.pdf", file_text),
      .,
      path = "pubfigures/pdf",
      device = cairo_pdf, ## cairo_pdf() to embed fonts, keep spaces
      width = 7, height = file_ht, units = "in"
    ) %T>%
    ggsave(
      filename = sprintf("mindusa_tteby%s.png", file_text),
      .,
      path = "pubfigures/png",
      type = "cairo", dpi = 400, width = 7, height = file_ht, units = "in"
    )
  
}

## Save all effect modification plots
pwalk(
  .l = list(
    median_df = list(
      mental_medians_age, mental_medians_iqcode, mental_medians_medsurg,
      mental_medians_sepsis, mental_medians_sofa
    ),
    em_string = c("age", "IQCODE", "ICU type", "sepsis", "modified SOFA"),
    title_text = c(
      "Age at Consent", "IQCODE at Consent",
      "Medical vs Surgical ICU Admission",
      "Sepsis/Septic Shock at ICU Admission",
      "Severity of Illness at Randomization"
    ),
    file_text = c("age", "iqcode", "medsurg", "sepsis", "modsofa"),
    file_ht = c(10, 7.5, 6, 6.5, 10)
  ),
  .f = save_mental_em_pub
)

pwalk(
  .l = list(
    ratio_df = list(
      tte_ratios_age, tte_ratios_iqcode, tte_ratios_medsurg, tte_ratios_sepsis,
      tte_ratios_sofa
    ),
    em_string = c("age", "IQCODE", "ICU type", "sepsis", "modified SOFA"),
    title_text = c(
      "Age at Consent", "IQCODE at Consent",
      "Medical vs Surgical ICU Admission",
      "Sepsis/Septic Shock at ICU Admission",
      "Severity of Illness at Randomization"
    ),
    file_text = c("age", "iqcode", "medsurg", "sepsis", "modsofa"),
    file_ht = c(10, 7.5, 6, 6.5, 10)
  ),
  .f = save_tte_em_pub
)

Notes on Variable Calculation


Severity of Illness

Due to the nature of clinical data collection, we had some missing values for APACHE II and SOFA components despite our coordinators’ best efforts. We handled these missing values in the following ways:

APACHE II (ICU admission only)

  • Oxygenation: If no arterial blood gas was done, we converted the lowest O2 saturation to PaO2 per the EPIC II conversions and assigned points based on PaO2 alone. O2 saturations below the lowest level included in the conversion table were assigned the lowest PaO2; O2 saturations of 100 were assigned the highest PaO2.
  • pH: If no arterial blood gas was done, we used the serum HCO3 conversions noted in the original reference.
  • Glasgow Coma Score: If no GCS was available, we assigned points for the APACHE using the lowest RASS on the day of ICU admission using Vasilevskis et al’s point values for the SOFA.
  • All other components: If no values were available on a given day, we looked for a value on the closest day within the three full days after ICU admission. If none was available, we assumed that no measurement implied no clinical reason to suspect dysfunction, and assigned a normal value (0 points).

SOFA (ICU admission + daily throughout intervention period)

  • Substitutions for specific components:
    • Respiratory: If P/F ratio was not available, we used the lowest S/F ratio, per Pandharipande et al.
    • Central nervous system: If no GCS was available, we used the lowest RASS available that day, per Vasilevskis et al, method C.
  • Missing data at ICU admission:

    Using only data from ICU admission, there are 28 consented patients and 7 randomized patients missing at least one SOFA component score. For these patients’ missing components, we imputed the next available value within the following two calendar days. If none was available, we assumed a normal value (0 points). (This could happen either because there was no clinical reason to order labs, or because the patient was not consented within three days of ICU admission and thus no study data was collected in that period.)

  • Missing data during the intervention period:
    • We were unable to calculate SOFA scores using raw data on 3 patient-days during the study period (randomization + 13 days). (Missingness is much higher after the official intervention/post-intervention periods, when patients were no longer being actively followed for daily data collection. However, in this analysis we are only concerned about the official 14-day study period.)
    • If the data required to calculate a given component was unavailable, we imputed the closest non-missing component score before or after the missing day, up to two full days away (missing day +/-2 days). If data was available X days both before and after the missing day, we prioritized past over future values.
    • If, after this imputation, values are still missing, we assume that no available data indicates no clinical reason to suspect organ dysfunction and therefore impute a normal value for that component. Again, this applies to 3 patient-days during the study period.

Medications

  • Benzodiazepines include midazolam, lorazepam, and/or diazepam. Doses are expressed in midazolam equivalents.
  • Opioids include fentanyl, morphine, and/or hydromorphone. Doses are expressed in fentanyl equivalents.
  • Antipsychotics include open-label haloperidol, open-label ziprasidone, quetiapine, aripiprazole, olanzapine (including in combination with fluoxetine), and/or risperidone. Doses are expressed in haloperidol equivalents.
  • All conversion formulas can be found in this spreadsheet.

Mechanical Ventilation

During the course of the study, patients could be on invasive mechanical ventilation (invasive MV), noninvasive positive pressure support (NIPPV), both, or neither. For our purposes, “time on MV” describes the number of days each patient was on either type of ventilation beginning at the time of randomization, including time between discontinuation of MV and reinitiation or death, if that time is less than 48 hours. (In other words, if a patient was extubated at 12pm and died at 3pm, those final three hours are included in the total time on MV.)

“Liberation from mechanical ventilation” indicates the first discontinuation of either type of MV which was followed by at least 48 hours alive without reinitiation of MV.

Delirium/Coma-Free Days (+ Other Mental Status Variables)

This primary outcome variable is calculated over the 14 days including and immediately following randomization. It is defined as days alive and without brain dysfunction.

For example, a patient who was delirious on the day of consent and the day following; had one day of normal status; again became delirious for one day; and was then comatose for two days before dying in the ICU would have 14 - (3 days delirium + 2 days coma + 8 days deceased) = 1 DCFD.

Patients are assumed to have normal mental status after being discharged alive from the hospital. Patients who withdrew from the study, and were therefore no longer assessed by research staff, have any remaining assessments during their intervention period considered missing. (Eg, a patient who withdrew on the afternoon of study day 10, allowed study staff to continue accessing their medical record, and was known to die on study day 13 would be considered to have missing assessments on study days 11 & 12.)

Patients who had study drug temporarily or permanently stopped, but did not withdraw from the study, continued to have their mental status assessed by study staff, so assessments are still available.

Determining Mental Status Using CAM and RASS

We determined mental status for a given assessment using the following criteria:

  1. Comatose: RASS -4 or -5, or RASS missing and CAM Unable to Assess
  2. Delirious: RASS missing or >= -3, and CAM Positive
    • Hyperactive delirium: Delirium with RASS +1 or higher
    • Hypoactive delirium: Delirium with RASS 0 or lower
  3. Normal: RASS missing or >= -3, and CAM Negative

If the patient’s RASS was -3 or higher, but the CAM was marked Unable to Assess, this information was marked as conflicting and the assessment was considered to be missing.

Patients could have multiple assessments on a given study day. On a given day, a patient was considered delirious if any assessment was considered delirious; comatose if no assessments met criteria for delirium and at least one was considered comatose; and normal if no assessments met criteria for delirium or coma, and at least one was considered normal.

Handling Missing Data

Despite the best efforts of our coordinators, we had a small amount of missing data on the assessment and daily level. The following table describes the amount of missingness by assessment and by day, for both all in-hospital days (pre-randomization, intervention, post-intervention, among all consented patients) and all in-hospital days during the intervention period among randomized patients only (the period during which all our mental status outcomes are calculated).

## -- Among all consented patients, how many assessments are missing? ----------
n_asmts_ih_total <- nrow(padasmts_df)
n_asmts_ih_miss_rc <- with(padasmts_df, sum(is.na(rass_raw) | is.na(cam_raw)))
n_asmts_ih_miss_ronly <-
  with(padasmts_df, sum(is.na(rass_raw) & !is.na(cam_raw)))
n_asmts_ih_miss_conly <-
  with(padasmts_df, sum(!is.na(rass_raw) & is.na(cam_raw)))
n_asmts_ih_miss_both <-
  with(padasmts_df, sum(is.na(rass_raw) & is.na(cam_raw)))

## How many days are missing all assessments?
n_days_ih_total <- nrow(
  unique(subset(padasmts_df, select = c(id, redcap_event_name)))
)
n_days_ih_missrc <- nrow(
  padasmts_df %>%
    mutate(miss_rc = is.na(rass_raw) | is.na(cam_raw)) %>%
    group_by(id, redcap_event_name) %>%
    summarise(has_rc = sum(!miss_rc)) %>%
    ungroup() %>%
    filter(has_rc == 0)
)

n_asmts_int_total <- nrow(pad_int_df)
n_asmts_int_miss_rc <- with(pad_int_df, sum(is.na(rass_raw) | is.na(cam_raw)))
n_asmts_int_miss_ronly <-
  with(pad_int_df, sum(is.na(rass_raw) & !is.na(cam_raw)))
n_asmts_int_miss_conly <-
  with(pad_int_df, sum(!is.na(rass_raw) & is.na(cam_raw)))
n_asmts_int_miss_both <-
  with(pad_int_df, sum(is.na(rass_raw) & is.na(cam_raw)))

## How many days are missing all assessments?
n_days_int_total <- nrow(
  unique(subset(pad_int_df, select = c(id, redcap_event_name)))
)
n_days_int_missrc <- nrow(
  pad_int_df %>%
    mutate(miss_rc = is.na(rass_raw) | is.na(cam_raw)) %>%
    group_by(id, redcap_event_name) %>%
    summarise(has_rc = sum(!miss_rc)) %>%
    ungroup() %>%
    filter(has_rc == 0)
)

## -- Make a table -------------------------------------------------------------
missing_mental <- tribble(
  ~ rowlabel,             ~ n_ih,                ~ n_int,
  "Assessments Possible", n_asmts_ih_total,      n_asmts_int_total,
  "RASS *or* CAM",        n_asmts_ih_miss_rc,    n_asmts_int_miss_rc,
  "Only RASS",            n_asmts_ih_miss_ronly, n_asmts_int_miss_ronly,
  "Only CAM",             n_asmts_ih_miss_conly, n_asmts_int_miss_conly,
  "RASS + CAM",           n_asmts_ih_miss_both,  n_asmts_int_miss_both,
  "Days Possible",        n_days_ih_total,       n_days_int_total,
  "Days with All Assessments Missing", n_days_ih_missrc, n_days_int_missrc
) %>%
  mutate(
    d_ih = c(
      NA, n_asmts_ih_total, rep(n_asmts_ih_miss_rc, 3), NA, n_days_ih_total
    ),
    d_int = c(
      NA, n_asmts_int_total, rep(n_asmts_int_miss_rc, 3), NA, n_days_int_total
    ),
    npct_ih = ifelse(is.na(d_ih), as.character(n_ih), get_npct(n_ih, d_ih)),
    npct_int = ifelse(is.na(d_int), as.character(n_int), get_npct(n_int, d_int))
  )

missing_mental %>%
  dplyr::select(rowlabel, npct_ih, npct_int) %>%
  kable(
    format = "html",
    align = c("l", "r", "r"),
    col.names = c(
      "",
      "All In-Hospital Days",
      "In-Hospital, Randomized, Intervention Phase"
    )
  ) %>%
  group_rows("Assessments missing...", 2, 5) %>%
  mykablestyle()
All In-Hospital Days In-Hospital, Randomized, Intervention Phase
Assessments Possible 15714 10113
Assessments missing…
RASS or CAM 1147 (7%) 736 (7%)
Only RASS 21 (2%) 12 (2%)
Only CAM 69 (6%) 48 (7%)
RASS + CAM 1057 (92%) 676 (92%)
Days Possible 9408 6100
Days with All Assessments Missing 376 (4%) 300 (5%)

Reasons Individual Assessments Missing

The following table describes the documented reasons that RASS and/or CAM assessments were missing during the intervention phase. (Assessments which are listed as died and/or discharged might be where a patient had a morning assessment, and was then discharged prior to the afternoon assessment.) Descriptions of “other” reasons are listed below (click to unfurl).

Reasons for Missing Assessments during Intervention Phase.
N

N=10113
Reason RASS not performed 412
    Patient off floor 13% 54412
    Patient in procedure 16% 67412
    Family refused 19% 77412
    Patient refused 7% 28412
    Other 22% 91412
    Died, discharged, DQ or w/d prior to assessment 23% 95412
Reason CAM-ICU not performed 448
    Patient off floor 12% 53448
    Patient in procedure 15% 69448
    Family refused 19% 85448
    Patient refused 11% 48448
    Other 22% 98448
    Died, discharged, DQ or w/d prior to assessment 21% 95448
N is the number of non-missing values.

“Other” Reasons Assessments Not Done

RASS Explanation CAM-ICU Explanation
Missed assessment Missed assessment
No study staff in hospital No study staff in hospital
No study staff in hospital No study staff in hospital
Nurse refused due to CMO status Nurse refused due to CMO status
Nurse refused due to CMO status Nurse refused due to CMO status
ntf ntf
ntf ntf
NA Not done by RN
See NTF see NTF
Weekend - RC forgot to schedule w/k coverage Weekend - RC forgot to schedule w/k coverage
Weekend - RC forgot to schedule w/k coverage Weekend - RC forgot to schedule w/k coverage
Patient transfered to Hospice before completed Patient transfered to Hospice before completed
NA unable to complete due to pain and restlessness
NA RASS -4, unable to complete. Staff believe due to Seroquel the night before
patient transitioning to comfort care patient transitioning to comfort care
patient transitioning to comfort care patient transitioning to comfort care
Patient being transitioned to comfort care Patient being transitioned to comfort care
Patient being transitioned to comfort care Patient being transitioned to comfort care
pt unavailable NA
Pt on comfort care measures Pt on comfort care measures
Pt on comfort care measures Pt on comfort care measures
Team states patient is moving to comfort care and they request we don’t assess Team states patient is moving to comfort care and they request we don’t assess
Team states patient is moving to comfort care and they request we don’t assess Team states patient is moving to comfort care and they request we don’t assess
Team states patient is moving to comfort care and they request we don’t assess Team states patient is moving to comfort care and they request we don’t assess
Team states patient is moving to comfort care and they request we don’t assess Team states patient is moving to comfort care and they request we don’t assess
NA Pt recovering from epistaxis episode; per RN pt is delirious
PT passed away at 12:42 pm PT passed away at 12:42 pm
Pt. passed away Pt. passed away
Study team did not follow patient once he was transferred out of the ICU. Study team did not follow patient once he was transferred out of the ICU.
Study team did not follow patient once he was transferred out of the ICU. Study team did not follow patient once he was transferred out of the ICU.
Study team did not follow patient once he was transferred out of the ICU. Study team did not follow patient once he was transferred out of the ICU.
Study team did not follow patient once he was transferred out of the ICU. Study team did not follow patient once he was transferred out of the ICU.
Study team did not follow patient once he was transferred out of the ICU. Study team did not follow patient once he was transferred out of the ICU.
Study team did not follow patient once he was transferred out of the ICU. Study team did not follow patient once he was transferred out of the ICU.
Study team did not follow patient once he was transferred out of the ICU. Study team did not follow patient once he was transferred out of the ICU.
Study team did not follow patient once he was transferred out of the ICU. Study team did not follow patient once he was transferred out of the ICU.
Study coordinator did not complete Study coordinator did not complete
assesment was not done by study coordinator assesment was not done by study coordinator
tx to floor tx out of ICU
tx out ICU Tx out of ICU
Unknown Unknown
Unknown Unknown
Unknown Unknown
Unknown Unknown
Unknown Unknown
Unknown Unknown
Unknown Unknown
Unknown Unknown
Unknown Unknown
Unknown Unknown
Patient receieved paralysis for Trach at 9:00am Patient receieved paralysis for Trach at 9:00am
NA Nurse requested I not wake patient due to his propensity to de-sat quickly. Patient’s vent setting had to be raised just prior to request to assess
Patient died Patient died
patient died Patient died
DNRCC DNRCC
NA Patient has a RASS of -4
Per site Manager since patient is in Hospice care Per site Manager since patient is in Hospice Care
misunderstanding about duration of study phases misunderstanding about duration of study phases
misunderstanding about duration of study phases misunderstanding about duration of study phases
pt transitioning to comfort care pt transitioning to comfort care
pt. comfort care pt. comfort care
pt. comfort care pt. comfort care
pt. comfort care pt. comfort care
pt comfort care pt comfort care
Patient coded Patient coded
Comfort Care Comfort Care
Comfort Care Comfort Care
done but not recorded NA
Comfort care Comfort care
attending physician refused attending physician refused
Added from Randomization Qual form. No data available except CAM+ NA
This is the CAM+ at randomization on this day at 12:05. This will be the pts only CAM+ and was needed for analysis. All variables changed have a history comment in the field comment log. No individual features available. At the original time 0925 the RASS = -5 and the CAM was UTA. NA
Withdrawn Withdrawn
Withdrawn Withdrawn
Patient discharged, see NTF patient discharged, see NTF
patient discharged patient discharged
Forgot to assess patient this day. Forgot to assess patient this day.
Patient passed away Patient passed away
patient passed away patient passed away
unknown noncompliance found in dataclean. See NTF unknown noncompliance found in dataclean. See NTF
found in dataclean. unknown noncompliance NA
Transition to comfort care Transition to comfort care
Transition to comfort care Transition to comfort care
NA Palliative Care Protocol
Added from Randomization Qual form. No data available except CAM+ NA
extubated @ 11:45 NA
see above see above
see above see above
Not known Discovered in Data Clean Not known Discovered in Data Clean
Not known Discovered in Data Clean Not known Discovered in Data Clean
Not known Discovered in Data Clean Not known Discovered in Data Clean
Not known Discovered in Data Clean Not known Discovered in Data Clean

Mental status can change quickly; therefore simple imputation methods like last observation carried forward could be inaccurate. Since we are fortunate to have strong covariate data, we performed single imputation to impute individual missing RASS and CAM scores, including the following variables as covariates in the imputation. We used predictive mean matching and polytomous logistic regression as the imputation methods, respectively, within R’s mice package.

  • Baseline: Age at consent; gender; BMI; education; level of proficiency in English; insurance; home antipsychotic use; Charlson comorbidities index; CSHA Clinical Frailty Score; APACHE II APS
  • Daily:
    • Medications (clonazepam, dexmedetomidine, propofol, remifentanil, antipsychotics, benzodiazepines, opioids [IV and PO], antibiotics, anxiolytics, statins)
    • Variables indicating severity of illness (CV SOFA, creatinine, urine output, platelets, lowest recorded RASS, Glasgow Coma Scale, P/F ratio, S/F ratio, bilirubin)
    • Any mental status data available the day of, the day before, and the day after the missing day

After any missing RASS and CAM values were imputed, we then determined all mental statuses (whether patients were comatose, delirious, hyperactively delirious, and hypoactively delirious) based on these imputed values and the algorithm noted above.

All summary variables (delirium/coma-free days, delirium duration, and coma duration) are presented using imputed mental status.

Software Details


R version 3.4.4 (2018-03-15) was used for all analyses. Table 14, collapsed below, shows all add-on packages loaded.

We also used R for all data management. Links to all R code for both data management and this analysis can be found on the Open Science Framework.

We use the checkpoint package for reproducibility. This package downloaded R package versions on CRAN as of May 14, 2018, and will use these versions going forward, regardless of future software updates. (The ggthemr and JTHelpers packages, solely housed on Github, were also installed in this directory on the same date.)

R Packages Used for Analysis

Table 14: Software Details

Package
Version Date Source
acepack 1.4.1 2016-10-29 CRAN (R 3.4.4)
assertthat 0.2.0 2017-04-11 CRAN (R 3.4.4)
backports 1.1.2 2017-12-13 cran (@1.1.2)
base
3.4.4 2018-03-16 local
base64enc 0.1-3 2015-07-28 CRAN (R 3.4.4)
bindr 0.1.1 2018-03-13 CRAN (R 3.4.4)
bindrcpp
0.2.2 2018-03-29 CRAN (R 3.4.4)
broom 0.4.4 2018-03-29 CRAN (R 3.4.4)
captioner
2.2.3 2015-07-16 CRAN (R 3.4.4)
checkmate 1.8.5 2017-10-24 CRAN (R 3.4.4)
checkpoint
0.4.3 2017-12-19 CRAN (R 3.4.4)
cluster 2.0.7-1 2018-04-09 CRAN (R 3.4.4)
cmprsk
2.2-7 2014-06-17 CRAN (R 3.4.4)
codetools 0.2-15 2016-10-05 CRAN (R 3.4.2)
colorspace 1.3-2 2016-12-14 CRAN (R 3.4.4)
compiler 3.4.4 2018-03-16 local
crosstalk 1.0.0 2016-12-21 CRAN (R 3.4.4)
data.table 1.11.2 2018-05-08 CRAN (R 3.4.4)
datasets
3.4.4 2018-03-16 local
devtools 1.13.5 2018-02-18 CRAN (R 3.4.4)
digest 0.6.18 2018-10-10 cran (@0.6.18)
dplyr
0.7.4 2017-09-28 CRAN (R 3.4.4)
DT
0.4 2018-01-30 CRAN (R 3.4.4)
evaluate 0.10.1 2017-06-24 CRAN (R 3.4.1)
extrafont
0.17 2014-12-08 CRAN (R 3.4.4)
extrafontdb 1.0 2012-06-11 CRAN (R 3.4.4)
forcats
0.3.0 2018-02-19 CRAN (R 3.4.4)
foreign 0.8-70 2018-04-23 CRAN (R 3.4.4)
Formula
1.2-3 2018-05-03 CRAN (R 3.4.4)
ggplot2
2.2.1 2016-12-30 CRAN (R 3.4.4)
ggpubr
0.1.6 2017-11-14 CRAN (R 3.4.4)
ggthemr
1.1.0 2018-05-14 Github (cttobin/ggthemr@0a31bb5)
glue
1.2.0 2017-10-29 CRAN (R 3.4.4)
graphics
3.4.4 2018-03-16 local
grDevices
3.4.4 2018-03-16 local
grid
3.4.4 2018-03-16 local
gridExtra 2.3 2017-09-09 CRAN (R 3.4.4)
gtable 0.2.0 2016-02-26 CRAN (R 3.4.4)
highr 0.6 2016-05-09 CRAN (R 3.4.4)
Hmisc
4.1-1 2018-01-03 CRAN (R 3.4.4)
hms 0.4.2 2018-03-10 CRAN (R 3.4.4)
htmlTable 1.11.2 2018-01-20 CRAN (R 3.4.4)
htmltools 0.3.6 2017-04-28 CRAN (R 3.4.1)
htmlwidgets 1.2 2018-04-19 CRAN (R 3.4.4)
httpuv 1.4.3 2018-05-10 CRAN (R 3.4.4)
httr 1.3.1 2017-08-20 CRAN (R 3.4.4)
jsonlite 1.5 2017-06-01 CRAN (R 3.4.4)
JTHelpers
0.0.0.9000 2018-05-14 Github (jenniferthompson/JTHelpers@0ce6de6)
kableExtra
0.8.0 2018-04-05 CRAN (R 3.4.4)
km.ci 0.5-2 2009-08-30 CRAN (R 3.4.4)
KMsurv 0.1-5 2012-12-03 CRAN (R 3.4.4)
knitr
1.20 2018-02-20 CRAN (R 3.4.3)
labeling 0.3 2014-08-23 CRAN (R 3.4.4)
later 0.7.2 2018-05-01 CRAN (R 3.4.4)
lattice
0.20-35 2017-03-25 CRAN (R 3.3.3)
latticeExtra 0.6-28 2016-02-09 CRAN (R 3.4.4)
lazyeval 0.2.1 2017-10-29 CRAN (R 3.4.4)
lmtest 0.9-36 2018-04-04 CRAN (R 3.4.4)
magrittr
1.5 2014-11-22 CRAN (R 3.4.1)
MASS
7.3-50 2018-04-30 CRAN (R 3.4.4)
Matrix 1.2-14 2018-04-09 CRAN (R 3.4.4)
MatrixModels 0.4-1 2015-08-22 CRAN (R 3.4.4)
memoise 1.1.0 2017-04-21 CRAN (R 3.4.4)
methods
3.4.4 2018-03-16 local
mice
2.46.0 2017-10-24 cran (@2.46.0)
mime 0.5 2016-07-07 CRAN (R 3.4.4)
mnormt 1.5-5 2016-10-15 CRAN (R 3.4.4)
multcomp 1.4-8 2017-11-08 CRAN (R 3.4.4)
munsell 0.4.3 2016-02-13 CRAN (R 3.4.4)
mvtnorm 1.0-7 2018-01-26 CRAN (R 3.4.4)
naniar
0.2.0 2018-02-09 CRAN (R 3.4.4)
nlme 3.1-137 2018-04-07 CRAN (R 3.4.4)
nnet 7.3-12 2016-02-02 CRAN (R 3.4.0)
parallel 3.4.4 2018-03-16 local
pillar 1.2.2 2018-04-26 CRAN (R 3.4.4)
pkgconfig 2.0.1 2017-03-21 CRAN (R 3.4.4)
plyr 1.8.4 2016-06-08 CRAN (R 3.4.4)
polspline 1.1.12 2015-07-14 CRAN (R 3.4.4)
promises 1.0.1 2018-04-13 CRAN (R 3.4.4)
psych 1.8.4 2018-05-06 CRAN (R 3.4.4)
purrr
0.2.4 2017-10-18 CRAN (R 3.4.4)
quantreg 5.35 2018-02-02 CRAN (R 3.4.4)
R6 2.2.2 2017-06-17 CRAN (R 3.4.4)
RColorBrewer 1.1-2 2014-12-07 CRAN (R 3.4.4)
Rcpp 0.12.19 2018-10-01 cran (@0.12.19)
readr 1.1.1 2017-05-16 CRAN (R 3.4.4)
reshape2 1.4.3 2017-12-11 CRAN (R 3.4.4)
rlang 0.2.0 2018-02-20 CRAN (R 3.4.4)
rmarkdown 1.10 2018-06-11 CRAN (R 3.4.4)
rms
5.1-2 2018-01-07 CRAN (R 3.4.4)
rpart 4.1-13 2018-02-23 CRAN (R 3.4.3)
rprojroot 1.3-2 2018-01-03 cran (@1.3-2)
rstudioapi 0.7 2017-09-07 CRAN (R 3.4.4)
Rttf2pt1 1.3.6 2018-02-22 CRAN (R 3.4.4)
rvest 0.3.2 2016-06-17 CRAN (R 3.4.4)
sandwich 2.4-0 2017-07-26 CRAN (R 3.4.4)
scales 0.5.0 2017-08-24 CRAN (R 3.4.4)
selectr 0.4-1 2018-04-06 CRAN (R 3.4.4)
shiny 1.0.5 2017-08-23 CRAN (R 3.4.4)
sparkline
2.0 2016-11-12 CRAN (R 3.4.4)
SparseM
1.77 2017-04-23 CRAN (R 3.4.4)
splines 3.4.4 2018-03-16 local
stats
3.4.4 2018-03-16 local
stringi 1.2.4 2018-07-20 cran (@1.2.4)
stringr 1.3.1 2018-05-10 cran (@1.3.1)
survival
2.42-6 2018-07-13 CRAN (R 3.4.4)
survminer
0.4.2 2018-01-31 CRAN (R 3.4.4)
survMisc 0.5.4 2016-11-23 CRAN (R 3.4.4)
TH.data 1.0-8 2017-01-23 CRAN (R 3.4.4)
tibble 1.4.2 2018-01-22 CRAN (R 3.4.4)
tidyr
0.8.0 2018-01-29 CRAN (R 3.4.4)
tidyselect 0.2.4 2018-02-26 CRAN (R 3.4.4)
tools 3.4.4 2018-03-16 local
utils
3.4.4 2018-03-16 local
viridisLite 0.3.0 2018-02-01 CRAN (R 3.4.4)
visdat 0.1.0 2017-07-11 CRAN (R 3.4.4)
withr 2.1.2 2018-03-15 CRAN (R 3.4.4)
xml2 1.2.0 2018-01-24 CRAN (R 3.4.4)
xtable 1.8-2 2016-02-05 CRAN (R 3.4.4)
yaml 2.2.0 2018-07-25 cran (@2.2.0)
zoo 1.8-1 2018-01-08 CRAN (R 3.4.4)


  1. Harrell, Frank E. (2015) Regression Modeling Strategies. New York, NY: Springer.

  2. Fine, J., & Gray, R. (1999). A Proportional Hazards Model for the Subdistribution of a Competing Risk. Journal of the American Statistical Association, 94(446), 496-509. doi:10.2307/2670170

  3. Harrell, Frank E. (2015) Regression Modeling Strategies. New York, NY: Springer.

  4. Fine, J., & Gray, R. (1999). A Proportional Hazards Model for the Subdistribution of a Competing Risk. Journal of the American Statistical Association, 94(446), 496-509. doi:10.2307/2670170

  5. Fine, J., & Gray, R. (1999). A Proportional Hazards Model for the Subdistribution of a Competing Risk. Journal of the American Statistical Association, 94(446), 496-509. doi:10.2307/2670170

  6. Fine, J., & Gray, R. (1999). A Proportional Hazards Model for the Subdistribution of a Competing Risk. Journal of the American Statistical Association, 94(446), 496-509. doi:10.2307/2670170

  7. Fine, J., & Gray, R. (1999). A Proportional Hazards Model for the Subdistribution of a Competing Risk. Journal of the American Statistical Association, 94(446), 496-509. doi:10.2307/2670170